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>


Reply via email to