diff --git a/devlink/devlink.c b/devlink/devlink.c index a0cd6a47..b7494f85 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -383,6 +383,12 @@ static bool dl_no_arg(struct dl *dl) return dl_argc(dl) == 0; } +static void __pr_out_indent_newline(struct dl *dl) +{ + if (!g_indent_newline && !dl->json_output) + pr_out(" "); +} + static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_BUS_NAME] = MNL_TYPE_NUL_STRING, [DEVLINK_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING, @@ -1852,14 +1858,11 @@ static void pr_out_port_handle_end(struct dl *dl) static void pr_out_str(struct dl *dl, const char *name, const char *val) { - if (dl->json_output) { + __pr_out_indent_newline(dl); + if (dl->json_output) jsonw_string_field(dl->jw, name, val); - } else { - if (g_indent_newline) - pr_out("%s %s", name, val); - else - pr_out(" %s %s", name, val); - } + else + pr_out("%s %s", name, val); } static void pr_out_bool(struct dl *dl, const char *name, bool val) @@ -1872,53 +1875,50 @@ static void pr_out_bool(struct dl *dl, const char *name, bool val) static void pr_out_uint(struct dl *dl, const char *name, unsigned int val) { - if (dl->json_output) { + __pr_out_indent_newline(dl); + if (dl->json_output) jsonw_uint_field(dl->jw, name, val); - } else { - if (g_indent_newline) - pr_out("%s %u", name, val); - else - pr_out(" %s %u", name, val); - } + else + pr_out("%s %u", name, val); } static void pr_out_u64(struct dl *dl, const char *name, uint64_t val) { + __pr_out_indent_newline(dl); if (val == (uint64_t) -1) return pr_out_str(dl, name, "unlimited"); - if (dl->json_output) { + if (dl->json_output) jsonw_u64_field(dl->jw, name, val); - } else { - if (g_indent_newline) - pr_out("%s %"PRIu64, name, val); - else - pr_out(" %s %"PRIu64, name, val); - } + else + pr_out("%s %"PRIu64, name, val); } static void pr_out_bool_value(struct dl *dl, bool value) { + __pr_out_indent_newline(dl); if (dl->json_output) jsonw_bool(dl->jw, value); else - pr_out(" %s", value ? "true" : "false"); + pr_out("%s", value ? "true" : "false"); } static void pr_out_uint_value(struct dl *dl, unsigned int value) { + __pr_out_indent_newline(dl); if (dl->json_output) jsonw_uint(dl->jw, value); else - pr_out(" %u", value); + pr_out("%u", value); } static void pr_out_uint64_value(struct dl *dl, uint64_t value) { + __pr_out_indent_newline(dl); if (dl->json_output) jsonw_u64(dl->jw, value); else - pr_out(" %"PRIu64, value); + pr_out("%"PRIu64, value); } static bool is_binary_eol(int i) @@ -1945,18 +1945,20 @@ static void pr_out_binary_value(struct dl *dl, uint8_t *data, uint32_t len) static void pr_out_str_value(struct dl *dl, const char *value) { + __pr_out_indent_newline(dl); if (dl->json_output) jsonw_string(dl->jw, value); else - pr_out(" %s", value); + pr_out("%s", value); } static void pr_out_name(struct dl *dl, const char *name) { + __pr_out_indent_newline(dl); if (dl->json_output) jsonw_name(dl->jw, name); else - pr_out(" %s:", name); + pr_out("%s:", name); } static void pr_out_region_chunk_start(struct dl *dl, uint64_t addr) @@ -6142,14 +6144,12 @@ static void pr_out_region_handle_end(struct dl *dl) static void pr_out_region_snapshots_start(struct dl *dl, bool array) { + __pr_out_indent_newline(dl); if (dl->json_output) { jsonw_name(dl->jw, "snapshot"); jsonw_start_array(dl->jw); } else { - if (g_indent_newline) - pr_out("snapshot %s", array ? "[" : ""); - else - pr_out(" snapshot %s", array ? "[" : ""); + pr_out("snapshot %s", array ? "[" : ""); } } @@ -6684,7 +6684,7 @@ static void pr_out_health(struct dl *dl, struct nlattr **tb_health) pr_out_handle_start_arr(dl, tb_health); - pr_out_str(dl, "name", + pr_out_str(dl, "reporter", mnl_attr_get_str(tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME])); if (!dl->json_output) { __pr_out_newline(); diff --git a/include/libnetlink.h b/include/libnetlink.h index 311cf3fc..8ebdc6d3 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 cd916ec8..879287e3 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 a883f210..20110ef0 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); - c = netns_map_get_by_nsid(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(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 8c490f89..6ce8b199 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) diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index a8ae72d2..31051c52 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -2364,7 +2364,6 @@ Commands: .BI dev " NAME " (default) .I NAME specifies the network device to show. -If this argument is omitted all devices in the default group are listed. .TP .BI group " GROUP " diff --git a/man/man8/ip-netns.8 b/man/man8/ip-netns.8 index 39a10e76..c75917da 100644 --- a/man/man8/ip-netns.8 +++ b/man/man8/ip-netns.8 @@ -31,6 +31,9 @@ ip-netns \- process network namespace management .B ip netns set .I NETNSNAME NETNSID +.ti -8 +.IR NETNSID " := " auto " | " POSITIVE-INT + .ti -8 .BR "ip netns identify" .RI "[ " PID " ]" @@ -48,6 +51,7 @@ ip-netns \- process network namespace management .ti -8 .BR "ip netns list-id" +.RI "[ target-nsid " POSITIVE-INT " ] [ nsid " POSITIVE-INT " ]" .SH DESCRIPTION A network namespace is logically another copy of the network stack, @@ -193,12 +197,28 @@ This command watches network namespace name addition and deletion events and prints a line for each event it sees. .TP -.B ip netns list-id - list network namespace ids (nsid) +.B ip netns list-id [target-nsid POSITIVE-INT] [nsid POSITIVE-INT] - list network namespace ids (nsid) .sp Network namespace ids are used to identify a peer network namespace. This -command displays nsid of the current network namespace and provides the +command displays nsids of the current network namespace and provides the corresponding iproute2 netns name (from /var/run/netns) if any. +The +.B target-nsid +option enables to display nsids of the specified network namespace instead of the current network +namespace. This +.B target-nsid +is a nsid from the current network namespace. + +The +.B nsid +option enables to display only this nsid. It is a nsid from the current network namespace. In +combination with the +.B target-nsid +option, it enables to convert a specific nsid from the current network namespace to a nsid of the +.B target-nsid +network namespace. + .SH EXAMPLES .PP ip netns list @@ -215,6 +235,31 @@ ip netns exec vpn ip link set lo up .RS Bring up the loopback interface in the vpn network namespace. .RE +.PP +ip netns add foo +.br +ip netns add bar +.br +ip netns set foo 12 +.br +ip netns set bar 13 +.br +ip -n foo netns set foo 22 +.br +ip -n foo netns set bar 23 +.br +ip -n bar netns set foo 32 +.br +ip -n bar netns set bar 33 +.br +ip netns list-id target-nsid 12 +.RS +Shows the list of nsids from the network namespace foo. +.RE +ip netns list-id target-nsid 12 nsid 13 +.RS +Get nsid of bar from the network namespace foo (result is 23). +.RE .SH SEE ALSO .br @@ -222,3 +267,5 @@ Bring up the loopback interface in the vpn network namespace. .SH AUTHOR Original Manpage by Eric W. Biederman +.br +Manpage revised by Nicolas Dichtel diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in index a61b263e..34763cc3 100644 --- a/man/man8/ip-route.8.in +++ b/man/man8/ip-route.8.in @@ -206,6 +206,8 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]" .IR TUNNEL_ID .B dst .IR REMOTE_IP " [ " +.B src +.IR SRC " ] [" .B tos .IR TOS " ] [" .B ttl @@ -740,11 +742,13 @@ is a set of encapsulation attributes specific to the .I TUNNEL_ID .B dst .IR REMOTE_IP " [ " +.B src +.IR SRC " ] [" .B tos .IR TOS " ] [" .B ttl .IR TTL " ] [ " -.BR key " ] [" csum " ] [ " seq " ] " +.BR key " ] [ " csum " ] [ " seq " ] " .in -2 .sp diff --git a/tc/m_gact.c b/tc/m_gact.c index dca2a2f9..b06e8ee9 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -87,7 +87,7 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p, return -1; if (!matches(*argv, "gact")) - NEXT_ARG_FWD(); + NEXT_ARG(); /* we're binding existing gact action to filter by index. */ if (!matches(*argv, "index")) goto skip_args;