Merge ssh://gitolite.kernel.org/pub/scm/network/iproute2/iproute2-next

This commit is contained in:
Stephen Hemminger
2024-12-01 16:29:17 -08:00
36 changed files with 597 additions and 127 deletions

20
.editorconfig Normal file
View File

@@ -0,0 +1,20 @@
# SPDX-License-Identifier: GPL-2.0
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 8
indent_style = tab
insert_final_newline = true
max_line_length = 100
tab_width = 8
trim_trailing_whitespace = true
[*.json]
indent_style = space
indent_size = 4
[{COMMIT_EDITMSG,*.patch}]
max_line_length = 75

View File

@@ -0,0 +1,2 @@
Each file in this directory is an rt_addrprotos configuration file. iproute2
commands scan this directory processing all files that end in '.conf'.

View File

@@ -24,6 +24,7 @@ int mnlu_gen_socket_sndrcv(struct mnlu_gen_socket *nlg, const struct nlmsghdr *n
mnl_cb_t data_cb, void *data);
struct mnl_socket *mnlu_socket_open(int bus);
int mnl_add_nl_group(struct mnl_socket *nl, unsigned int group);
struct nlmsghdr *mnlu_msg_prepare(void *buf, uint32_t nlmsg_type, uint16_t flags,
void *extra_header, size_t extra_header_size);
int mnlu_socket_recv_run(struct mnl_socket *nl, unsigned int seq, void *buf, size_t buf_size,

View File

@@ -11,6 +11,7 @@ const char *rtnl_rttable_n2a(__u32 id, char *buf, int len);
const char *rtnl_rtrealm_n2a(int id, char *buf, int len);
const char *rtnl_dsfield_n2a(int id, char *buf, int len);
const char *rtnl_dsfield_get_name(int id);
const char *rtnl_dscp_n2a(int id, char *buf, int len);
const char *rtnl_group_n2a(int id, char *buf, int len);
int rtnl_rtprot_a2n(__u32 *id, const char *arg);
@@ -19,6 +20,7 @@ int rtnl_rtscope_a2n(__u32 *id, const char *arg);
int rtnl_rttable_a2n(__u32 *id, const char *arg);
int rtnl_rtrealm_a2n(__u32 *id, const char *arg);
int rtnl_dsfield_a2n(__u32 *id, const char *arg);
int rtnl_dscp_a2n(__u32 *id, const char *arg);
int rtnl_group_a2n(int *id, const char *arg);
const char *inet_proto_n2a(int proto, char *buf, int len);

View File

@@ -37,6 +37,7 @@ extern int batch_mode;
extern int numeric;
extern bool do_all;
extern int echo_request;
extern int use_iec;
#ifndef CONF_USR_DIR
#define CONF_USR_DIR "/usr/lib/iproute2"
@@ -336,6 +337,7 @@ int get_time(unsigned int *time, const char *str);
int get_time64(__s64 *time, const char *str);
char *sprint_time(__u32 time, char *buf);
char *sprint_time64(__s64 time, char *buf);
void print_num(FILE *fp, unsigned int width, uint64_t count);
int do_batch(const char *name, bool force,
int (*cmd)(int argc, char *argv[], void *user), void *user);

View File

@@ -27,8 +27,6 @@
#endif
int preferred_family = AF_UNSPEC;
int human_readable;
int use_iec;
int show_stats;
int show_details;
int oneline;

View File

@@ -7,8 +7,6 @@
#include "json_print.h"
extern int use_iec;
struct link_filter {
int ifindex;
int family;
@@ -18,6 +16,7 @@ struct link_filter {
int scope, scopemask;
int flags, flagmask;
int up;
int down;
char *label;
int flushed;
char *flushb;
@@ -221,7 +220,6 @@ int ipstats_stat_desc_show_xstats(struct ipstats_stat_show_attrs *attrs,
#define LABEL_MAX_MASK 0xFFFFFU
#endif
void print_num(FILE *fp, unsigned int width, uint64_t count);
void print_rt_flags(FILE *fp, unsigned int flags);
void print_rta_ifidx(FILE *fp, __u32 ifidx, const char *prefix);
void __print_rta_gateway(FILE *fp, unsigned char family, const char *gateway);

View File

@@ -52,12 +52,12 @@ static void usage(void)
"Usage: ip address {add|change|replace} IFADDR dev IFNAME [ LIFETIME ]\n"
" [ CONFFLAG-LIST ]\n"
" ip address del IFADDR dev IFNAME [mngtmpaddr]\n"
" ip address {save|flush} [ dev IFNAME ] [ scope SCOPE-ID ]\n"
" [ to PREFIX ] [ FLAG-LIST ] [ label LABEL ] [up]\n"
" ip address {save|flush} [ dev IFNAME ] [ scope SCOPE-ID ] [ to PREFIX ]\n"
" [ FLAG-LIST ] [ label LABEL ] [ { up | down } ]\n"
" ip address [ show [ dev IFNAME ] [ scope SCOPE-ID ] [ master DEVICE ]\n"
" [ nomaster ]\n"
" [ type TYPE ] [ to PREFIX ] [ FLAG-LIST ]\n"
" [ label LABEL ] [up] [ vrf NAME ]\n"
" [ label LABEL ] [ { up | down } ] [ vrf NAME ]\n"
" [ proto ADDRPROTO ] ]\n"
" ip address {showdump|restore}\n"
"IFADDR := PREFIX | ADDR peer PREFIX\n"
@@ -568,46 +568,6 @@ void size_columns(unsigned int cols[], unsigned int n, ...)
va_end(args);
}
void print_num(FILE *fp, unsigned int width, uint64_t count)
{
const char *prefix = "kMGTPE";
const unsigned int base = use_iec ? 1024 : 1000;
uint64_t powi = 1;
uint16_t powj = 1;
uint8_t precision = 2;
char buf[64];
if (!human_readable || count < base) {
fprintf(fp, "%*"PRIu64" ", width, count);
return;
}
/* increase value by a factor of 1000/1024 and print
* if result is something a human can read
*/
for (;;) {
powi *= base;
if (count / base < powi)
break;
if (!prefix[1])
break;
++prefix;
}
/* try to guess a good number of digits for precision */
for (; precision > 0; precision--) {
powj *= 10;
if (count / powi < powj)
break;
}
snprintf(buf, sizeof(buf), "%.*f%c%s", precision,
(double) count / powi, *prefix, use_iec ? "i" : "");
fprintf(fp, "%*s ", width, buf);
}
static void print_vf_stats64(FILE *fp, struct rtattr *vfstats)
{
struct rtattr *vf[IFLA_VF_STATS_MAX + 1];
@@ -1021,6 +981,8 @@ int print_linkinfo(struct nlmsghdr *n, void *arg)
return -1;
if (filter.up && !(ifi->ifi_flags&IFF_UP))
return -1;
if (filter.down && ifi->ifi_flags&IFF_UP)
return -1;
parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, NLA_F_NESTED);
@@ -1760,6 +1722,9 @@ static int print_selected_addrinfo(struct ifinfomsg *ifi,
if (filter.up && !(ifi->ifi_flags&IFF_UP))
continue;
if (filter.down && ifi->ifi_flags&IFF_UP)
continue;
open_json_object(NULL);
print_addrinfo(n, fp);
close_json_object();
@@ -2180,6 +2145,8 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
filter.scope = scope;
} else if (strcmp(*argv, "up") == 0) {
filter.up = 1;
} else if (strcmp(*argv, "down") == 0) {
filter.down = 1;
} else if (get_filter(*argv) == 0) {
} else if (strcmp(*argv, "label") == 0) {

View File

@@ -110,8 +110,8 @@ void iplink_usage(void)
" [ gso_max_size BYTES ] [ gso_ipv4_max_size BYTES ] [ gso_max_segs PACKETS ]\n"
" [ gro_max_size BYTES ] [ gro_ipv4_max_size BYTES ]\n"
"\n"
" ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n"
" [nomaster] [ novf ]\n"
" ip link show [ DEVICE | group GROUP ] [ { up | down } ] [master DEV] [vrf NAME]\n"
" [type TYPE] [nomaster] [ novf ]\n"
"\n"
" ip link xstats type TYPE [ ARGS ]\n"
"\n"

View File

@@ -15,6 +15,12 @@
#include "utils.h"
#include "ip_common.h"
struct can_tdc {
__u32 tdcv;
__u32 tdco;
__u32 tdcf;
};
static void print_usage(FILE *f)
{
fprintf(f,
@@ -126,87 +132,86 @@ static void print_ctrlmode(enum output_type t, __u32 flags, const char* key)
static int can_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
struct can_bittiming bt = {}, dbt = {};
struct can_bittiming bt = {}, fd_dbt = {};
struct can_ctrlmode cm = { 0 };
struct rtattr *tdc;
__u32 tdcv = -1, tdco = -1, tdcf = -1;
struct can_tdc fd = { .tdcv = -1, .tdco = -1, .tdcf = -1 };
while (argc > 0) {
if (matches(*argv, "bitrate") == 0) {
NEXT_ARG();
if (get_u32(&bt.bitrate, *argv, 0))
invarg("invalid \"bitrate\" value\n", *argv);
invarg("invalid \"bitrate\" value", *argv);
} else if (matches(*argv, "sample-point") == 0) {
float sp;
NEXT_ARG();
if (get_float(&sp, *argv))
invarg("invalid \"sample-point\" value\n",
invarg("invalid \"sample-point\" value",
*argv);
bt.sample_point = (__u32)(sp * 1000);
} else if (matches(*argv, "tq") == 0) {
NEXT_ARG();
if (get_u32(&bt.tq, *argv, 0))
invarg("invalid \"tq\" value\n", *argv);
invarg("invalid \"tq\" value", *argv);
} else if (matches(*argv, "prop-seg") == 0) {
NEXT_ARG();
if (get_u32(&bt.prop_seg, *argv, 0))
invarg("invalid \"prop-seg\" value\n", *argv);
invarg("invalid \"prop-seg\" value", *argv);
} else if (matches(*argv, "phase-seg1") == 0) {
NEXT_ARG();
if (get_u32(&bt.phase_seg1, *argv, 0))
invarg("invalid \"phase-seg1\" value\n", *argv);
invarg("invalid \"phase-seg1\" value", *argv);
} else if (matches(*argv, "phase-seg2") == 0) {
NEXT_ARG();
if (get_u32(&bt.phase_seg2, *argv, 0))
invarg("invalid \"phase-seg2\" value\n", *argv);
invarg("invalid \"phase-seg2\" value", *argv);
} else if (matches(*argv, "sjw") == 0) {
NEXT_ARG();
if (get_u32(&bt.sjw, *argv, 0))
invarg("invalid \"sjw\" value\n", *argv);
invarg("invalid \"sjw\" value", *argv);
} else if (matches(*argv, "dbitrate") == 0) {
NEXT_ARG();
if (get_u32(&dbt.bitrate, *argv, 0))
invarg("invalid \"dbitrate\" value\n", *argv);
if (get_u32(&fd_dbt.bitrate, *argv, 0))
invarg("invalid \"dbitrate\" value", *argv);
} else if (matches(*argv, "dsample-point") == 0) {
float sp;
NEXT_ARG();
if (get_float(&sp, *argv))
invarg("invalid \"dsample-point\" value\n", *argv);
dbt.sample_point = (__u32)(sp * 1000);
invarg("invalid \"dsample-point\" value", *argv);
fd_dbt.sample_point = (__u32)(sp * 1000);
} else if (matches(*argv, "dtq") == 0) {
NEXT_ARG();
if (get_u32(&dbt.tq, *argv, 0))
invarg("invalid \"dtq\" value\n", *argv);
if (get_u32(&fd_dbt.tq, *argv, 0))
invarg("invalid \"dtq\" value", *argv);
} else if (matches(*argv, "dprop-seg") == 0) {
NEXT_ARG();
if (get_u32(&dbt.prop_seg, *argv, 0))
invarg("invalid \"dprop-seg\" value\n", *argv);
if (get_u32(&fd_dbt.prop_seg, *argv, 0))
invarg("invalid \"dprop-seg\" value", *argv);
} else if (matches(*argv, "dphase-seg1") == 0) {
NEXT_ARG();
if (get_u32(&dbt.phase_seg1, *argv, 0))
invarg("invalid \"dphase-seg1\" value\n", *argv);
if (get_u32(&fd_dbt.phase_seg1, *argv, 0))
invarg("invalid \"dphase-seg1\" value", *argv);
} else if (matches(*argv, "dphase-seg2") == 0) {
NEXT_ARG();
if (get_u32(&dbt.phase_seg2, *argv, 0))
invarg("invalid \"dphase-seg2\" value\n", *argv);
if (get_u32(&fd_dbt.phase_seg2, *argv, 0))
invarg("invalid \"dphase-seg2\" value", *argv);
} else if (matches(*argv, "dsjw") == 0) {
NEXT_ARG();
if (get_u32(&dbt.sjw, *argv, 0))
invarg("invalid \"dsjw\" value\n", *argv);
if (get_u32(&fd_dbt.sjw, *argv, 0))
invarg("invalid \"dsjw\" value", *argv);
} else if (matches(*argv, "tdcv") == 0) {
NEXT_ARG();
if (get_u32(&tdcv, *argv, 0))
invarg("invalid \"tdcv\" value\n", *argv);
if (get_u32(&fd.tdcv, *argv, 0))
invarg("invalid \"tdcv\" value", *argv);
} else if (matches(*argv, "tdco") == 0) {
NEXT_ARG();
if (get_u32(&tdco, *argv, 0))
invarg("invalid \"tdco\" value\n", *argv);
if (get_u32(&fd.tdco, *argv, 0))
invarg("invalid \"tdco\" value", *argv);
} else if (matches(*argv, "tdcf") == 0) {
NEXT_ARG();
if (get_u32(&tdcf, *argv, 0))
invarg("invalid \"tdcf\" value\n", *argv);
if (get_u32(&fd.tdcf, *argv, 0))
invarg("invalid \"tdcf\" value", *argv);
} else if (matches(*argv, "loopback") == 0) {
NEXT_ARG();
set_ctrlmode("loopback", *argv, &cm,
@@ -255,10 +260,8 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
cm.mask |= CAN_CTRLMODE_TDC_AUTO |
CAN_CTRLMODE_TDC_MANUAL;
} else {
fprintf(stderr,
"Error: argument of \"tdc-mode\" must be \"auto\", \"manual\" or \"off\", not \"%s\"\n",
invarg("\"tdc-mode\" must be either of \"auto\", \"manual\" or \"off\"",
*argv);
exit (-1);
}
} else if (matches(*argv, "restart") == 0) {
__u32 val = 1;
@@ -269,14 +272,14 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
NEXT_ARG();
if (get_u32(&val, *argv, 0))
invarg("invalid \"restart-ms\" value\n", *argv);
invarg("invalid \"restart-ms\" value", *argv);
addattr32(n, 1024, IFLA_CAN_RESTART_MS, val);
} else if (matches(*argv, "termination") == 0) {
__u16 val;
NEXT_ARG();
if (get_u16(&val, *argv, 0))
invarg("invalid \"termination\" value\n",
invarg("invalid \"termination\" value",
*argv);
addattr16(n, 1024, IFLA_CAN_TERMINATION, val);
} else if (matches(*argv, "help") == 0) {
@@ -292,19 +295,21 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
if (bt.bitrate || bt.tq)
addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
if (dbt.bitrate || dbt.tq)
addattr_l(n, 1024, IFLA_CAN_DATA_BITTIMING, &dbt, sizeof(dbt));
if (fd_dbt.bitrate || fd_dbt.tq)
addattr_l(n, 1024, IFLA_CAN_DATA_BITTIMING, &fd_dbt, sizeof(fd_dbt));
if (cm.mask)
addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
if (tdcv != -1 || tdco != -1 || tdcf != -1) {
tdc = addattr_nest(n, 1024, IFLA_CAN_TDC | NLA_F_NESTED);
if (tdcv != -1)
addattr32(n, 1024, IFLA_CAN_TDC_TDCV, tdcv);
if (tdco != -1)
addattr32(n, 1024, IFLA_CAN_TDC_TDCO, tdco);
if (tdcf != -1)
addattr32(n, 1024, IFLA_CAN_TDC_TDCF, tdcf);
if (fd.tdcv != -1 || fd.tdco != -1 || fd.tdcf != -1) {
struct rtattr *tdc = addattr_nest(n, 1024,
IFLA_CAN_TDC | NLA_F_NESTED);
if (fd.tdcv != -1)
addattr32(n, 1024, IFLA_CAN_TDC_TDCV, fd.tdcv);
if (fd.tdco != -1)
addattr32(n, 1024, IFLA_CAN_TDC_TDCO, fd.tdco);
if (fd.tdcf != -1)
addattr32(n, 1024, IFLA_CAN_TDC_TDCF, fd.tdcf);
addattr_nest_end(n, tdc);
}
@@ -337,7 +342,7 @@ can_print_timing_min_max(const char *json_attr, const char *fp_attr,
close_json_object();
}
static void can_print_tdc_opt(FILE *f, struct rtattr *tdc_attr)
static void can_print_tdc_opt(struct rtattr *tdc_attr)
{
struct rtattr *tb[IFLA_CAN_TDC_MAX + 1];
@@ -365,7 +370,7 @@ static void can_print_tdc_opt(FILE *f, struct rtattr *tdc_attr)
}
}
static void can_print_tdc_const_opt(FILE *f, struct rtattr *tdc_attr)
static void can_print_tdc_const_opt(struct rtattr *tdc_attr)
{
struct rtattr *tb[IFLA_CAN_TDC_MAX + 1];
@@ -393,7 +398,7 @@ static void can_print_tdc_const_opt(FILE *f, struct rtattr *tdc_attr)
close_json_object();
}
static void can_print_ctrlmode_ext(FILE *f, struct rtattr *ctrlmode_ext_attr,
static void can_print_ctrlmode_ext(struct rtattr *ctrlmode_ext_attr,
__u32 cm_flags)
{
struct rtattr *tb[IFLA_CAN_CTRLMODE_MAX + 1];
@@ -417,7 +422,7 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
print_ctrlmode(PRINT_ANY, cm->flags, "ctrlmode");
if (tb[IFLA_CAN_CTRLMODE_EXT])
can_print_ctrlmode_ext(f, tb[IFLA_CAN_CTRLMODE_EXT],
can_print_ctrlmode_ext(tb[IFLA_CAN_CTRLMODE_EXT],
cm->flags);
}
@@ -542,7 +547,7 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
print_uint(PRINT_ANY, "brp", " dbrp %u", dbt->brp);
if (tb[IFLA_CAN_TDC])
can_print_tdc_opt(f, tb[IFLA_CAN_TDC]);
can_print_tdc_opt(tb[IFLA_CAN_TDC]);
close_json_object();
}
@@ -566,7 +571,7 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
print_uint(PRINT_ANY, "brp_inc", " dbrp_inc %u", dbtc->brp_inc);
if (tb[IFLA_CAN_TDC])
can_print_tdc_const_opt(f, tb[IFLA_CAN_TDC]);
can_print_tdc_const_opt(tb[IFLA_CAN_TDC]);
close_json_object();
}

View File

@@ -46,6 +46,7 @@ static void usage(void)
" [ ipproto PROTOCOL ]\n"
" [ sport [ NUMBER | NUMBER-NUMBER ]\n"
" [ dport [ NUMBER | NUMBER-NUMBER ] ]\n"
" [ dscp DSCP ]\n"
"ACTION := [ table TABLE_ID ]\n"
" [ protocol PROTO ]\n"
" [ nat ADDRESS ]\n"
@@ -67,6 +68,7 @@ static struct
unsigned int tos, tosmask;
unsigned int pref, prefmask;
unsigned int fwmark, fwmask;
unsigned int dscp, dscpmask;
uint64_t tun_id;
char iif[IFNAMSIZ];
char oif[IFNAMSIZ];
@@ -219,6 +221,17 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
}
}
if (filter.dscpmask) {
if (tb[FRA_DSCP]) {
__u8 dscp = rta_getattr_u8(tb[FRA_DSCP]);
if (filter.dscp != dscp)
return false;
} else {
return false;
}
}
table = frh_get_table(frh, tb);
if (filter.tb > 0 && filter.tb ^ table)
return false;
@@ -468,6 +481,14 @@ int print_rule(struct nlmsghdr *n, void *arg)
rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
}
}
if (tb[FRA_DSCP]) {
__u8 dscp = rta_getattr_u8(tb[FRA_DSCP]);
print_string(PRINT_ANY, "dscp", " dscp %s",
rtnl_dscp_n2a(dscp, b1, sizeof(b1)));
}
print_string(PRINT_FP, NULL, "\n", "");
close_json_object();
fflush(fp);
@@ -697,6 +718,14 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
else if (ret != 2)
invarg("invalid dport range\n", *argv);
filter.dport = r;
} else if (strcmp(*argv, "dscp") == 0) {
__u32 dscp;
NEXT_ARG();
if (rtnl_dscp_a2n(&dscp, *argv))
invarg("invalid dscp\n", *argv);
filter.dscp = dscp;
filter.dscpmask = 1;
} else {
if (matches(*argv, "dst") == 0 ||
matches(*argv, "to") == 0) {
@@ -975,6 +1004,13 @@ static int iprule_modify(int cmd, int argc, char **argv)
invarg("invalid dport range\n", *argv);
addattr_l(&req.n, sizeof(req), FRA_DPORT_RANGE, &r,
sizeof(r));
} else if (strcmp(*argv, "dscp") == 0) {
__u32 dscp;
NEXT_ARG();
if (rtnl_dscp_a2n(&dscp, *argv))
invarg("invalid dscp\n", *argv);
addattr8(&req.n, sizeof(req), FRA_DSCP, dscp);
} else {
int type;

View File

@@ -35,6 +35,11 @@ err_bind:
return NULL;
}
int mnl_add_nl_group(struct mnl_socket *nl, unsigned int group)
{
return mnl_socket_bind(nl, group, MNL_SOCKET_AUTOPID);
}
struct nlmsghdr *mnlu_msg_prepare(void *buf, uint32_t nlmsg_type, uint16_t flags,
void *extra_header, size_t extra_header_size)
{

View File

@@ -315,6 +315,9 @@ static void rtnl_addrprot_initialize(void)
ret = rtnl_tab_initialize(CONF_USR_DIR "/rt_addrprotos",
rtnl_addrprot_tab,
ARRAY_SIZE(rtnl_addrprot_tab));
rtnl_tab_initialize_dir("rt_addrprotos.d", rtnl_addrprot_tab,
ARRAY_SIZE(rtnl_addrprot_tab));
}
const char *rtnl_addrprot_n2a(__u8 id, char *buf, int len)
@@ -625,6 +628,17 @@ const char *rtnl_dsfield_get_name(int id)
return rtnl_rtdsfield_tab[id];
}
const char *rtnl_dscp_n2a(int id, char *buf, int len)
{
if (!numeric) {
const char *name = rtnl_dsfield_get_name(id << 2);
if (name != NULL)
return name;
}
snprintf(buf, len, "%u", id);
return buf;
}
int rtnl_dsfield_a2n(__u32 *id, const char *arg)
{
@@ -658,6 +672,18 @@ int rtnl_dsfield_a2n(__u32 *id, const char *arg)
return 0;
}
int rtnl_dscp_a2n(__u32 *id, const char *arg)
{
if (get_u32(id, arg, 0) == 0)
return 0;
if (rtnl_dsfield_a2n(id, arg) != 0)
return -1;
/* Convert from DS field to DSCP */
*id >>= 2;
return 0;
}
static struct rtnl_hash_entry dflt_group_entry = {
.id = 0, .name = "default"

View File

@@ -7,6 +7,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <math.h>
#include <unistd.h>
#include <fcntl.h>
@@ -38,6 +39,8 @@
int resolve_hosts;
int timestamp_short;
int pretty;
int use_iec;
int human_readable;
const char *_SL_ = "\n";
static int open_fds[5];
@@ -2021,6 +2024,46 @@ FILE *generic_proc_open(const char *env, const char *name)
return fopen(p, "r");
}
void print_num(FILE *fp, unsigned int width, uint64_t count)
{
const char *prefix = "kMGTPE";
const unsigned int base = use_iec ? 1024 : 1000;
uint64_t powi = 1;
uint16_t powj = 1;
uint8_t precision = 2;
char buf[64];
if (!human_readable || count < base) {
fprintf(fp, "%*"PRIu64" ", width, count);
return;
}
/* increase value by a factor of 1000/1024 and print
* if result is something a human can read
*/
for (;;) {
powi *= base;
if (count / base < powi)
break;
if (!prefix[1])
break;
++prefix;
}
/* try to guess a good number of digits for precision */
for (; precision > 0; precision--) {
powj *= 10;
if (count / powi < powj)
break;
}
snprintf(buf, sizeof(buf), "%.*f%c%s", precision,
(double) count / powi, *prefix, use_iec ? "i" : "");
fprintf(fp, "%*s ", width, buf);
}
int open_fds_add(int fd)
{
if (open_fds_cnt >= ARRAY_SIZE(open_fds))
@@ -2030,7 +2073,6 @@ int open_fds_add(int fd)
return 0;
}
void open_fds_close(void)
{
int i;

1
man/man8/.gitignore vendored
View File

@@ -3,3 +3,4 @@ ip-address.8
ip-link.8
ip-netns.8
ip-route.8
ip-rule.8

View File

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
TARGETS = ip-address.8 ip-link.8 ip-netns.8 ip-route.8
TARGETS = ip-address.8 ip-link.8 ip-netns.8 ip-route.8 ip-rule.8
MAN8PAGES = $(TARGETS) $(filter-out $(TARGETS),$(wildcard *.8))

View File

@@ -32,7 +32,7 @@ ip-address \- protocol address management
.B to
.IR PREFIX " ] [ " FLAG-LIST " ] [ "
.B label
.IR PATTERN " ] [ " up " ]"
.IR PATTERN " ] [ { " up " | " down " } ]"
.ti -8
.BR "ip address" " [ " show " [ " dev
@@ -48,8 +48,8 @@ ip-address \- protocol address management
.B type
.IR TYPE " ] [ "
.B vrf
.IR NAME " ] [ "
.BR up " ] ["
.IR NAME " ] [ { "
.BR up " | " down " } ] ["
.BR nomaster " ]"
.B proto
.IR ADDRPROTO " ] ]"
@@ -303,7 +303,10 @@ receive multicast traffic.
the protocol identifier of this route.
.I ADDRPROTO
may be a number or a string from the file
.BR "/etc/iproute2/rt_addrprotos" .
.BR @SYSCONF_USR_DIR@/rt_addrprotos " or " @SYSCONF_ETC_DIR@/rt_addrprotos
(has precedence if exists). A directory named
.BR rt_addrprotos.d
is also scanned in either location.
If the protocol ID is not given,
.B ip assumes protocol 0. Several protocol
@@ -378,6 +381,10 @@ output.
.B up
only list running interfaces.
.TP
.B down
only list not running interfaces.
.TP
.B nomaster
only list interfaces with no master.

View File

@@ -194,8 +194,8 @@ ip-link \- network device configuration
.B ip link show
.RI "[ " DEVICE " | "
.B group
.IR GROUP " ] ["
.BR up " ] ["
.IR GROUP " ] [ { "
.BR up " | " down " } ] ["
.B master
.IR DEVICE " ] ["
.B type
@@ -2903,6 +2903,10 @@ specifies what group of devices to show.
.B up
only display running interfaces.
.TP
.B down
only display not running interfaces.
.TP
.BI master " DEVICE "
.I DEVICE

View File

@@ -36,6 +36,8 @@ ip-rule \- routing policy database management
.IR PREFIX " ] [ "
.B tos
.IR TOS " ] [ "
.B dscp
.IR DSCP " ] [ "
.B fwmark
.IR FWMARK\fR[\fB/\fIMASK "] ] [ "
.B iif
@@ -234,6 +236,21 @@ a device.
.BI dsfield " TOS"
select the TOS value to match.
.TP
.BI dscp " DSCP"
select the DSCP value to match. DSCP values can be written either directly as
numeric values (valid values are 0-63), or using symbolic names specified in
.BR @SYSCONF_USR_DIR@/rt_dsfield " or " @SYSCONF_ETC_DIR@/rt_dsfield
(has precedence if exists).
However, note that the file specifies full 8-bit dsfield values, whereas
.B ip rule
will only use the higher six bits.
.B ip rule show
will similarly format DSCP values as symbolic names if possible. The
command line option
.B -N
turns the show translation off.
.TP
.BI fwmark " MARK"
select the

View File

@@ -6,7 +6,7 @@ rdma-link \- rdma link configuration
.ad l
.in +8
.ti -8
.B devlink
.B rdma
.RI "[ " OPTIONS " ]"
.B link
.RI " { " COMMAND " | "

51
man/man8/rdma-monitor.8 Normal file
View File

@@ -0,0 +1,51 @@
.TH RDMA\-MONITOR 8 "22 Jul 2024" "iproute2" "Linux"
.SH NAME
rdma-monitor \- RDMA events monitoring
.SH SYNOPSIS
.sp
.ad l
.in +8
.ti -8
.B rdma
.RI "[ " OPTIONS " ]"
.B monitor
.RI " { " help " }"
.sp
.ti -8
.IR OPTIONS " := { "
\fB\-V\fR[\fIersion\fR] }
.ti -8
.B rdma monitor
.ti -8
.B rdma monitor help
.SH "DESCRIPTION"
.SS rdma monitor - utility can monitor RDMA device events on all RDMA devices.
.PP
.B rdma
opens an RDMA Netlink socket, listens on it and dumps the event info.
The event types supported are RDMA device registration/unregistration
and net device attachment/detachment.
.SH "EXAMPLES"
.PP
rdma monitor
.RS 4
Listen for events of all RDMA devices
.RE
.PP
.SH SEE ALSO
.BR rdma (8),
.BR rdma-link (8),
.BR rdma-resource (8),
.BR rdma-system (8),
.BR rdma-statistic (8),
.br
.SH AUTHOR
Chiara Meiohas <cmeiohas@nvidia.com>

View File

@@ -38,8 +38,8 @@ rdma-system \- RDMA subsystem configuration
.SS rdma system set - set RDMA subsystem network namespace mode or
privileged qkey mode
.SS rdma system show - display RDMA subsystem network namespace mode and
privileged qkey state
.SS rdma system show - display RDMA subsystem network namespace mode,
privileged qkey state and whether RDMA monitoring is supported.
.PP
.I "NEWMODE"
@@ -66,8 +66,8 @@ controlled QKEY or not.
.PP
rdma system show
.RS 4
Shows the state of RDMA subsystem network namespace mode on the system and
the state of privileged qkey parameter.
Shows the state of RDMA subsystem network namespace mode on the system,
the state of privileged qkey parameter and whether RDMA monitor is supported.
.RE
.PP
rdma system set netns exclusive
@@ -100,6 +100,7 @@ is *not* allowed to specify a controlled QKEY.
.BR rdma (8),
.BR rdma-link (8),
.BR rdma-resource (8),
.BR rdma-monitor (8),
.BR network_namespaces (7),
.BR namespaces (7),
.br

View File

@@ -19,7 +19,7 @@ rdma \- RDMA tool
.ti -8
.IR OBJECT " := { "
.BR dev " | " link " | " resource " | " system " | " statistic " }"
.BR dev " | " link " | " resource " | " system " | " statistic " | " monitor " }"
.sp
.ti -8
@@ -94,6 +94,10 @@ character.
.B statistic
- RDMA counter statistic related.
.TP
.B monitor
- RDMA events monitor
.PP
The names of all objects may be written in full or
abbreviated form, for example
@@ -133,6 +137,7 @@ Exit status is 0 if command was successful or a positive integer upon failure.
.BR rdma-resource (8),
.BR rdma-system (8),
.BR rdma-statistic (8),
.BR rdma-monitor (8),
.br
.SH REPORTING BUGS

View File

@@ -115,14 +115,28 @@ parameters in a single schedule. Each one has the
sched-entry <command> <gatemask> <interval>
format. The only supported <command> is "S", which
means "SetGateStates", following the IEEE 802.1Q-2018 definition
(Table 8-7). <gate mask> is a bitmask where each bit is a associated
with a traffic class, so bit 0 (the least significant bit) being "on"
means that traffic class 0 is "active" for that schedule entry.
<interval> is a time duration, in nanoseconds, that specifies for how
long that state defined by <command> and <gate mask> should be held
before moving to the next entry.
format.
<command> support the following values:
.br
.I "S"
for SetGateStates
.br
.I "H"
for Set-And-Hold-MAC
.br
.I "R"
for Set-And-Release-MAC
.br
These commands follow the IEEE 802.1Q-2018 definition (Table 8-7).
<gate mask> is a bitmask where each bit is associated with a traffic class, so
bit 0 (the least significant bit) being "on" means that traffic class 0 is
"active" for that schedule entry.
<interval> is a time duration, in nanoseconds, that specifies for how long that
state defined by <command> and <gate mask> should be held before moving to
the next entry.
.TP
flags

View File

@@ -50,6 +50,12 @@ vdpa-dev \- vdpa device configuration
.B qidx
.I QUEUE_INDEX
.ti -8
.B vdpa dev set
.B name
.I NAME
.B mac
.RI "[ " MACADDR " ]"
.SH "DESCRIPTION"
.SS vdpa dev show - display vdpa device attributes
@@ -120,6 +126,15 @@ VDPA_DEVICE_NAME
.BI qidx " QUEUE_INDEX"
- specifies the virtqueue index to query
.SS vdpa dev set - set the configuration to the vdpa device.
.BI name " NAME"
-Name of the vdpa device to configure.
.BI mac " MACADDR"
- specifies the mac address for the vdpa device.
This is applicable only for the network type of vdpa device.
.SH "EXAMPLES"
.PP
vdpa dev show
@@ -171,6 +186,11 @@ vdpa dev vstats show vdpa0 qidx 1
.RS 4
Shows vendor specific statistics information for vdpa device vdpa0 and virtqueue index 1
.RE
.PP
vdpa dev set name vdpa0 mac 00:11:22:33:44:55
.RS 4
Set a specific MAC address to vdpa device vdpa0
.RE
.SH SEE ALSO
.BR vdpa (8),

View File

@@ -4,7 +4,8 @@ include ../config.mk
CFLAGS += -I./include/uapi/
RDMA_OBJ = rdma.o utils.o dev.o link.o res.o res-pd.o res-mr.o res-cq.o \
res-cmid.o res-qp.o sys.o stat.o stat-mr.o res-ctx.o res-srq.o
res-cmid.o res-qp.o sys.o stat.o stat-mr.o res-ctx.o res-srq.o \
monitor.o
TARGETS += rdma

View File

@@ -638,6 +638,8 @@ enum rdma_nl_notify_event_type {
RDMA_UNREGISTER_EVENT,
RDMA_NETDEV_ATTACH_EVENT,
RDMA_NETDEV_DETACH_EVENT,
RDMA_RENAME_EVENT,
RDMA_NETDEV_RENAME_EVENT,
};
#endif /* _RDMA_NETLINK_H */

209
rdma/monitor.c Normal file
View File

@@ -0,0 +1,209 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* monitor.c RDMA tool
* Authors: Chiara Meiohas <cmeiohas@nvidia.com>
*/
#include "rdma.h"
#include "utils.h"
static int mon_is_supported_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
uint8_t *is_sup = data;
mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
if (tb[RDMA_NLDEV_SYS_ATTR_MONITOR_MODE])
*is_sup = mnl_attr_get_u8(tb[RDMA_NLDEV_SYS_ATTR_MONITOR_MODE]);
return MNL_CB_OK;
}
static int mon_is_supported(struct rd *rd, uint8_t *is_sup)
{
uint32_t seq;
int ret;
*is_sup = 0;
rd_prepare_msg(rd, RDMA_NLDEV_CMD_SYS_GET,
&seq, (NLM_F_REQUEST | NLM_F_ACK));
ret = rd_send_msg(rd);
if (ret)
return ret;
return rd_recv_msg(rd, mon_is_supported_cb, is_sup, seq);
}
static void mon_print_event_type(struct nlattr **tb)
{
const char *const event_types_str[] = {
[RDMA_REGISTER_EVENT] = "[REGISTER]",
[RDMA_UNREGISTER_EVENT] = "[UNREGISTER]",
[RDMA_NETDEV_ATTACH_EVENT] = "[NETDEV_ATTACH]",
[RDMA_NETDEV_DETACH_EVENT] = "[NETDEV_DETACH]",
[RDMA_RENAME_EVENT] = "[RENAME]",
[RDMA_NETDEV_RENAME_EVENT] = "[NETDEV_RENAME]",
};
enum rdma_nl_notify_event_type etype;
char unknown_type[32];
if (!tb[RDMA_NLDEV_ATTR_EVENT_TYPE])
return;
etype = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_EVENT_TYPE]);
if (etype < ARRAY_SIZE(event_types_str) && event_types_str[etype]) {
print_string(PRINT_ANY, "event_type", "%s\t",
event_types_str[etype]);
} else {
snprintf(unknown_type, sizeof(unknown_type), "[UNKNOWN 0x%02x]",
etype);
print_string(PRINT_ANY, "event_type", "%s\t", unknown_type);
}
}
static int mon_print_dev(struct nlattr **tb)
{
const char *name;
uint32_t idx;
if (tb[RDMA_NLDEV_ATTR_DEV_INDEX]) {
idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
print_uint(PRINT_ANY, "rdma_index", "dev %u", idx);
}
if(tb[RDMA_NLDEV_ATTR_DEV_NAME]) {
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
print_string(PRINT_ANY, "rdma_dev", " %s", name);
}
return 0;
}
static void mon_print_port_idx(struct nlattr **tb)
{
uint32_t port;
if (tb[RDMA_NLDEV_ATTR_PORT_INDEX]) {
port = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
print_uint(PRINT_ANY, "port", " port %u", port);
}
}
static void mon_print_netdev(struct nlattr **tb)
{
uint32_t netdev_idx;
const char *name;
if (tb[RDMA_NLDEV_ATTR_NDEV_INDEX]) {
netdev_idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_NDEV_INDEX]);
print_uint(PRINT_ANY, "netdev_idx", " netdev %u", netdev_idx);
}
if(tb[RDMA_NLDEV_ATTR_NDEV_NAME]) {
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_NDEV_NAME]);
print_string(PRINT_ANY, "netdev_name", " %s", name);
}
}
static int mon_show_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX + 1] = {};
mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
if (!tb[RDMA_NLDEV_ATTR_EVENT_TYPE])
return MNL_CB_ERROR;
open_json_object(NULL);
mon_print_event_type(tb);
mon_print_dev(tb);
mon_print_port_idx(tb);
mon_print_netdev(tb);
close_json_object();
newline();
fflush(stdout);
return MNL_CB_OK;
}
static int mon_show(struct rd* rd)
{
unsigned int groups = 0;
uint8_t is_sup = 0;
int one = 1;
char *buf;
int err;
err = mon_is_supported(rd, &is_sup);
if (err) {
pr_err("Failed to check if RDMA monitoring is supported\n");
return err;
}
if (!is_sup) {
pr_err("RDMA monitoring is not supported by the kernel\n");
return -ENOENT;
}
buf = malloc(MNL_SOCKET_BUFFER_SIZE);
if (!buf) {
pr_err("Buffer allocation failed\n");
return -ENOMEM;
}
rd->nl = mnl_socket_open(NETLINK_RDMA);
if (!rd->nl) {
pr_err("Failed to open NETLINK_RDMA socket. Error: %s\n",
strerror(errno));
err = -ENODEV;
goto err_free;
}
mnl_socket_setsockopt(rd->nl, NETLINK_CAP_ACK, &one, sizeof(one));
mnl_socket_setsockopt(rd->nl, NETLINK_EXT_ACK, &one, sizeof(one));
groups |= nl_mgrp(RDMA_NL_GROUP_NOTIFY);
err = mnl_add_nl_group(rd->nl, groups);
if (err < 0) {
pr_err("Failed to add NETLINK_RDMA multicast group. Error: %s\n",
strerror(errno));
goto err_close;
}
new_json_obj(json);
err = mnlu_socket_recv_run(rd->nl, 0, buf, MNL_SOCKET_BUFFER_SIZE,
mon_show_cb, rd);
if (err) {
pr_err("Failed to listen to rdma socket\n");
goto err_free_json;
}
return 0;
err_free_json:
delete_json_obj();
err_close:
mnl_socket_close(rd->nl);
err_free:
free(buf);
return err;
}
static int mon_help(struct rd *rd)
{
pr_out("Usage: rdma monitor [ -j ]\n");
return 0;
}
int cmd_mon(struct rd *rd)
{
const struct rd_cmd cmds[] = {
{ NULL, mon_show },
{ "help", mon_help },
{ 0 }
};
return rd_exec_cmd(rd, cmds, "mon command");
}

View File

@@ -15,7 +15,7 @@ static void help(char *name)
{
pr_out("Usage: %s [ OPTIONS ] OBJECT { COMMAND | help }\n"
" %s [ -f[orce] ] -b[atch] filename\n"
"where OBJECT := { dev | link | resource | system | statistic | help }\n"
"where OBJECT := { dev | link | resource | monitor | system | statistic | help }\n"
" OPTIONS := { -V[ersion] | -d[etails] | -j[son] | -p[retty] | -r[aw]}\n", name, name);
}
@@ -35,6 +35,7 @@ static int rd_cmd(struct rd *rd, int argc, char **argv)
{ "resource", cmd_res },
{ "system", cmd_sys },
{ "statistic", cmd_stat },
{ "monitor", cmd_mon },
{ 0 }
};

View File

@@ -98,6 +98,7 @@ int cmd_link(struct rd *rd);
int cmd_res(struct rd *rd);
int cmd_sys(struct rd *rd);
int cmd_stat(struct rd *rd);
int cmd_mon(struct rd* rd);
int rd_exec_cmd(struct rd *rd, const struct rd_cmd *c, const char *str);
int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd));
int rd_exec_require_dev(struct rd *rd, int (*cb)(struct rd *rd));

View File

@@ -20,6 +20,7 @@ static const char *netns_modes_str[] = {
static int sys_show_parse_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
uint8_t mon_mode = 0;
bool cof = false;
mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
@@ -48,6 +49,10 @@ static int sys_show_parse_cb(const struct nlmsghdr *nlh, void *data)
}
if (tb[RDMA_NLDEV_SYS_ATTR_MONITOR_MODE])
mon_mode = mnl_attr_get_u8(tb[RDMA_NLDEV_SYS_ATTR_MONITOR_MODE]);
print_on_off(PRINT_ANY, "monitor", "monitor %s ", mon_mode);
if (tb[RDMA_NLDEV_SYS_ATTR_COPY_ON_FORK])
cof = mnl_attr_get_u8(tb[RDMA_NLDEV_SYS_ATTR_COPY_ON_FORK]);
@@ -77,6 +82,7 @@ static int sys_show(struct rd *rd)
{ NULL, sys_show_no_args},
{ "netns", sys_show_no_args},
{ "privileged-qkey", sys_show_no_args},
{ "monitor", sys_show_no_args},
{ 0 }
};

View File

@@ -477,6 +477,8 @@ static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
[RDMA_NLDEV_SYS_ATTR_PRIVILEGED_QKEY_MODE] = MNL_TYPE_U8,
[RDMA_NLDEV_ATTR_DEV_TYPE] = MNL_TYPE_U8,
[RDMA_NLDEV_ATTR_PARENT_NAME] = MNL_TYPE_STRING,
[RDMA_NLDEV_ATTR_EVENT_TYPE] = MNL_TYPE_U8,
[RDMA_NLDEV_SYS_ATTR_MONITOR_MODE] = MNL_TYPE_U8,
};
static int rd_attr_check(const struct nlattr *attr, int *typep)

View File

@@ -53,6 +53,10 @@ static const char *entry_cmd_to_str(__u8 cmd)
switch (cmd) {
case TC_TAPRIO_CMD_SET_GATES:
return "S";
case TC_TAPRIO_CMD_SET_AND_HOLD:
return "H";
case TC_TAPRIO_CMD_SET_AND_RELEASE:
return "R";
default:
return "Invalid";
}
@@ -62,6 +66,10 @@ static int str_to_entry_cmd(const char *str)
{
if (strcmp(str, "S") == 0)
return TC_TAPRIO_CMD_SET_GATES;
else if (strcmp(str, "H") == 0)
return TC_TAPRIO_CMD_SET_AND_HOLD;
else if (strcmp(str, "R") == 0)
return TC_TAPRIO_CMD_SET_AND_RELEASE;
return -1;
}

View File

@@ -31,7 +31,6 @@ int show_graph;
int timestamp;
int batch_mode;
int use_iec;
int force;
bool use_names;
int json;

View File

@@ -27,4 +27,3 @@ int check_size_table_opts(struct tc_sizespec *s);
extern int show_graph;
extern bool use_names;
extern int use_iec;

View File

@@ -759,6 +759,22 @@ static int cmd_dev_del(struct vdpa *vdpa, int argc, char **argv)
return mnlu_gen_socket_sndrcv(&vdpa->nlg, nlh, NULL, NULL);
}
static int cmd_dev_set(struct vdpa *vdpa, int argc, char **argv)
{
struct nlmsghdr *nlh;
int err;
nlh = mnlu_gen_socket_cmd_prepare(&vdpa->nlg, VDPA_CMD_DEV_ATTR_SET,
NLM_F_REQUEST | NLM_F_ACK);
err = vdpa_argv_parse_put(nlh, vdpa, argc, argv,
VDPA_OPT_VDEV_NAME,
VDPA_OPT_VDEV_MAC);
if (err)
return err;
return mnlu_gen_socket_sndrcv(&vdpa->nlg, nlh, NULL, NULL);
}
static void pr_out_dev_net_config(struct vdpa *vdpa, struct nlattr **tb)
{
SPRINT_BUF(macaddr);
@@ -1028,6 +1044,8 @@ static int cmd_dev(struct vdpa *vdpa, int argc, char **argv)
return cmd_dev_config(vdpa, argc - 1, argv + 1);
} else if (!strcmp(*argv, "vstats")) {
return cmd_dev_vstats(vdpa, argc - 1, argv + 1);
} else if (!strcmp(*argv, "set")) {
return cmd_dev_set(vdpa, argc - 1, argv + 1);
}
fprintf(stderr, "Command \"%s\" not found\n", *argv);
return -ENOENT;