Nicolas Dichtel píše v Po 07. 10. 2019 v 15:44 +0200: > This patch enables to dump/get nsid from a netns into another netns. > > Example: > $ ./test.sh > + ip netns add foo > + ip netns add bar > + touch /var/run/netns/init_net > + mount --bind /proc/1/ns/net /var/run/netns/init_net > + ip netns set init_net 11 > + ip netns set foo 12 > + ip netns set bar 13 > + ip netns > init_net (id: 11) > bar (id: 13) > foo (id: 12) > + ip -n foo netns set init_net 21 > + ip -n foo netns set foo 22 > + ip -n foo netns set bar 23 > + ip -n foo netns > init_net (id: 21) > bar (id: 23) > foo (id: 22) > + ip -n bar netns set init_net 31 > + ip -n bar netns set foo 32 > + ip -n bar netns set bar 33 > + ip -n bar netns > init_net (id: 31) > bar (id: 33) > foo (id: 32) > + ip netns list-id target-nsid 12 > nsid 21 current-nsid 11 (iproute2 netns name: init_net) > nsid 22 current-nsid 12 (iproute2 netns name: foo) > nsid 23 current-nsid 13 (iproute2 netns name: bar) > + ip -n foo netns list-id target-nsid 21 > nsid 11 current-nsid 21 (iproute2 netns name: init_net) > nsid 12 current-nsid 22 (iproute2 netns name: foo) > nsid 13 current-nsid 23 (iproute2 netns name: bar) > + ip -n bar netns list-id target-nsid 33 nsid 32 > nsid 32 current-nsid 32 (iproute2 netns name: foo) > + ip -n bar netns list-id target-nsid 31 nsid 32 > nsid 12 current-nsid 32 (iproute2 netns name: foo) > + ip netns list-id nsid 13 > nsid 13 (iproute2 netns name: bar) > > CC: Petr Oros <po...@redhat.com> > Signed-off-by: Nicolas Dichtel <nicolas.dich...@6wind.com> > --- > include/libnetlink.h | 5 +- > ip/ip_common.h | 1 + > ip/ipnetns.c | 115 +++++++++++++++++++++++++++++++++++++++++-- > lib/libnetlink.c | 15 ++++-- > 4 files changed, 126 insertions(+), 10 deletions(-) > > diff --git a/include/libnetlink.h b/include/libnetlink.h > index 311cf3fc90f8..8ebdc6d3d03e 100644 > --- a/include/libnetlink.h > +++ b/include/libnetlink.h > @@ -71,8 +71,6 @@ int rtnl_mdbdump_req(struct rtnl_handle *rth, int family) > __attribute__((warn_unused_result)); > int rtnl_netconfdump_req(struct rtnl_handle *rth, int family) > __attribute__((warn_unused_result)); > -int rtnl_nsiddump_req(struct rtnl_handle *rth, int family) > - __attribute__((warn_unused_result)); > > int rtnl_linkdump_req(struct rtnl_handle *rth, int fam) > __attribute__((warn_unused_result)); > @@ -85,6 +83,9 @@ int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, > int fam, > int rtnl_fdb_linkdump_req_filter_fn(struct rtnl_handle *rth, > req_filter_fn_t filter_fn) > __attribute__((warn_unused_result)); > +int rtnl_nsiddump_req_filter_fn(struct rtnl_handle *rth, int family, > + req_filter_fn_t filter_fn) > + __attribute__((warn_unused_result)); > int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 > filt_mask) > __attribute__((warn_unused_result)); > int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, > diff --git a/ip/ip_common.h b/ip/ip_common.h > index cd916ec87c26..879287e3e506 100644 > --- a/ip/ip_common.h > +++ b/ip/ip_common.h > @@ -24,6 +24,7 @@ struct link_filter { > int master; > char *kind; > char *slave_kind; > + int target_nsid; > }; > > int get_operstate(const char *name); > diff --git a/ip/ipnetns.c b/ip/ipnetns.c > index a883f210d7ba..20110ef0f58e 100644 > --- a/ip/ipnetns.c > +++ b/ip/ipnetns.c > @@ -36,7 +36,7 @@ static int usage(void) > " ip netns pids NAME\n" > " ip [-all] netns exec [NAME] cmd ...\n" > " ip netns monitor\n" > - " ip netns list-id\n" > + " ip netns list-id [target-nsid POSITIVE-INT] [nsid > POSITIVE-INT]\n" > "NETNSID := auto | POSITIVE-INT\n"); > exit(-1); > } > @@ -46,6 +46,7 @@ static struct rtnl_handle rtnsh = { .fd = -1 }; > > static int have_rtnl_getnsid = -1; > static int saved_netns = -1; > +static struct link_filter filter; > > static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl, > struct nlmsghdr *n, void *arg) > @@ -294,7 +295,7 @@ int print_nsid(struct nlmsghdr *n, void *arg) > FILE *fp = (FILE *)arg; > struct nsid_cache *c; > char name[NAME_MAX]; > - int nsid; > + int nsid, current; > > if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID) > return 0; > @@ -317,9 +318,22 @@ int print_nsid(struct nlmsghdr *n, void *arg) > print_bool(PRINT_ANY, "deleted", "Deleted ", true); > > nsid = rta_getattr_u32(tb[NETNSA_NSID]); > - print_uint(PRINT_ANY, "nsid", "nsid %u ", nsid); > + if (nsid < 0) > + print_string(PRINT_ANY, "nsid", "nsid %s ", "not-assigned"); > + else > + print_uint(PRINT_ANY, "nsid", "nsid %u ", nsid); > + > + if (tb[NETNSA_CURRENT_NSID]) { > + current = rta_getattr_u32(tb[NETNSA_CURRENT_NSID]); > + if (current < 0) > + print_string(PRINT_ANY, "current-nsid", > + "current-nsid %s ", "not-assigned"); > + else > + print_uint(PRINT_ANY, "current-nsid", > + "current-nsid %u ", current); > + } > > - c = netns_map_get_by_nsid(nsid); > + c = netns_map_get_by_nsid(tb[NETNSA_CURRENT_NSID] ? current : nsid); > if (c != NULL) { > print_string(PRINT_ANY, "name", > "(iproute2 netns name: %s)", c->name); > @@ -340,15 +354,106 @@ int print_nsid(struct nlmsghdr *n, void *arg) > return 0; > } > > +static int get_netnsid_from_netnsid(int nsid) > +{ > + struct { > + struct nlmsghdr n; > + struct rtgenmsg g; > + char buf[1024]; > + } req = { > + .n.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct > rtgenmsg))), > + .n.nlmsg_flags = NLM_F_REQUEST, > + .n.nlmsg_type = RTM_GETNSID, > + .g.rtgen_family = AF_UNSPEC, > + }; > + struct nlmsghdr *answer; > + int err; > + > + netns_nsid_socket_init(); > + > + err = addattr32(&req.n, sizeof(req), NETNSA_NSID, nsid); > + if (err) > + return err; > + > + if (filter.target_nsid >= 0) { > + err = addattr32(&req.n, sizeof(req), NETNSA_TARGET_NSID, > + filter.target_nsid); > + if (err) > + return err; > + } > + > + if (rtnl_talk(&rtnsh, &req.n, &answer) < 0) > + return -2; > + > + /* Validate message and parse attributes */ > + if (answer->nlmsg_type == NLMSG_ERROR) > + goto err_out; > + > + new_json_obj(json); > + err = print_nsid(answer, stdout); > + delete_json_obj(); > +err_out: > + free(answer); > + return err; > +} > + > +static int netns_filter_req(struct nlmsghdr *nlh, int reqlen) > +{ > + int err; > + > + if (filter.target_nsid >= 0) { > + err = addattr32(nlh, reqlen, NETNSA_TARGET_NSID, > + filter.target_nsid); > + if (err) > + return err; > + } > + > + return 0; > +} > + > static int netns_list_id(int argc, char **argv) > { > + int nsid = -1; > + > if (!ipnetns_have_nsid()) { > fprintf(stderr, > "RTM_GETNSID is not supported by the kernel.\n"); > return -ENOTSUP; > } > > - if (rtnl_nsiddump_req(&rth, AF_UNSPEC) < 0) { > + filter.target_nsid = -1; > + while (argc > 0) { > + if (strcmp(*argv, "target-nsid") == 0) { > + if (filter.target_nsid >= 0) > + duparg("target-nsid", *argv); > + NEXT_ARG(); > + > + if (get_integer(&filter.target_nsid, *argv, 0)) > + invarg("\"target-nsid\" value is invalid\n", > + *argv); > + else if (filter.target_nsid < 0) > + invarg("\"target-nsid\" value should be >= 0\n", > + argv[1]); > + } else if (strcmp(*argv, "nsid") == 0) { > + if (nsid >= 0) > + duparg("nsid", *argv); > + NEXT_ARG(); > + > + if (get_integer(&nsid, *argv, 0)) > + invarg("\"nsid\" value is invalid\n", *argv); > + else if (nsid < 0) > + invarg("\"nsid\" value should be >= 0\n", > + argv[1]); > + } else > + usage(); > + argc--; argv++; > + } > + > + if (nsid >= 0) > + return get_netnsid_from_netnsid(nsid); > + > + if (rtnl_nsiddump_req_filter_fn(&rth, AF_UNSPEC, > + netns_filter_req) < 0) { > perror("Cannot send dump request"); > exit(1); > } > diff --git a/lib/libnetlink.c b/lib/libnetlink.c > index 8c490f896326..6ce8b199f441 100644 > --- a/lib/libnetlink.c > +++ b/lib/libnetlink.c > @@ -438,12 +438,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, > @@ -451,8 +452,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)
Works great. Thanks, Nicolas. Tested-by: Petr Oros <po...@redhat.com>