mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-18 16:21:58 +00:00
Merge branch 'master' into next
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
commit
74ddde9b5f
@ -25,7 +25,6 @@
|
||||
#include <linux/devlink.h>
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "SNAPSHOT.h"
|
||||
#include "list.h"
|
||||
@ -1779,29 +1778,26 @@ static void pr_out_uint64_value(struct dl *dl, uint64_t value)
|
||||
pr_out(" %"PRIu64, value);
|
||||
}
|
||||
|
||||
static bool is_binary_eol(int i)
|
||||
{
|
||||
return !(i%16);
|
||||
}
|
||||
|
||||
static void pr_out_binary_value(struct dl *dl, uint8_t *data, uint32_t len)
|
||||
{
|
||||
int i = 1;
|
||||
|
||||
if (dl->json_output)
|
||||
jsonw_start_array(dl->jw);
|
||||
else
|
||||
pr_out("\n");
|
||||
int i = 0;
|
||||
|
||||
while (i < len) {
|
||||
if (dl->json_output) {
|
||||
if (dl->json_output)
|
||||
jsonw_printf(dl->jw, "%d", data[i]);
|
||||
} else {
|
||||
pr_out(" %02x", data[i]);
|
||||
if (!(i % 16))
|
||||
pr_out("\n");
|
||||
}
|
||||
else
|
||||
pr_out("%02x ", data[i]);
|
||||
i++;
|
||||
if (!dl->json_output && is_binary_eol(i))
|
||||
__pr_out_newline();
|
||||
}
|
||||
if (dl->json_output)
|
||||
jsonw_end_array(dl->jw);
|
||||
else if ((i - 1) % 16)
|
||||
pr_out("\n");
|
||||
if (!dl->json_output && !is_binary_eol(i))
|
||||
__pr_out_newline();
|
||||
}
|
||||
|
||||
static void pr_out_str_value(struct dl *dl, const char *value)
|
||||
@ -5982,35 +5978,36 @@ static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data)
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
struct nest_qentry {
|
||||
struct nest_entry {
|
||||
int attr_type;
|
||||
TAILQ_ENTRY(nest_qentry) nest_entries;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct fmsg_cb_data {
|
||||
struct dl *dl;
|
||||
uint8_t value_type;
|
||||
TAILQ_HEAD(, nest_qentry) qhead;
|
||||
struct list_head entry_list;
|
||||
};
|
||||
|
||||
static int cmd_fmsg_nest_queue(struct fmsg_cb_data *fmsg_data,
|
||||
uint8_t *attr_value, bool insert)
|
||||
{
|
||||
struct nest_qentry *entry = NULL;
|
||||
struct nest_entry *entry;
|
||||
|
||||
if (insert) {
|
||||
entry = malloc(sizeof(struct nest_qentry));
|
||||
entry = malloc(sizeof(struct nest_entry));
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
entry->attr_type = *attr_value;
|
||||
TAILQ_INSERT_HEAD(&fmsg_data->qhead, entry, nest_entries);
|
||||
list_add(&entry->list, &fmsg_data->entry_list);
|
||||
} else {
|
||||
if (TAILQ_EMPTY(&fmsg_data->qhead))
|
||||
if (list_empty(&fmsg_data->entry_list))
|
||||
return MNL_CB_ERROR;
|
||||
entry = TAILQ_FIRST(&fmsg_data->qhead);
|
||||
entry = list_first_entry(&fmsg_data->entry_list,
|
||||
struct nest_entry, list);
|
||||
*attr_value = entry->attr_type;
|
||||
TAILQ_REMOVE(&fmsg_data->qhead, entry, nest_entries);
|
||||
list_del(&entry->list);
|
||||
free(entry);
|
||||
}
|
||||
return MNL_CB_OK;
|
||||
@ -6105,13 +6102,13 @@ static int cmd_fmsg_object_cb(const struct nlmsghdr *nlh, void *data)
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int cmd_health_object_common(struct dl *dl, uint8_t cmd)
|
||||
static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags)
|
||||
{
|
||||
struct fmsg_cb_data data;
|
||||
struct nlmsghdr *nlh;
|
||||
int err;
|
||||
|
||||
nlh = mnlg_msg_prepare(dl->nlg, cmd, NLM_F_REQUEST | NLM_F_ACK);
|
||||
nlh = mnlg_msg_prepare(dl->nlg, cmd, flags | NLM_F_REQUEST | NLM_F_ACK);
|
||||
|
||||
err = dl_argv_parse_put(nlh, dl,
|
||||
DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0);
|
||||
@ -6119,19 +6116,23 @@ static int cmd_health_object_common(struct dl *dl, uint8_t cmd)
|
||||
return err;
|
||||
|
||||
data.dl = dl;
|
||||
TAILQ_INIT(&data.qhead);
|
||||
INIT_LIST_HEAD(&data.entry_list);
|
||||
err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_fmsg_object_cb, &data);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cmd_health_dump_show(struct dl *dl)
|
||||
{
|
||||
return cmd_health_object_common(dl, DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
|
||||
return cmd_health_object_common(dl,
|
||||
DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
|
||||
NLM_F_DUMP);
|
||||
}
|
||||
|
||||
static int cmd_health_diagnose(struct dl *dl)
|
||||
{
|
||||
return cmd_health_object_common(dl, DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE);
|
||||
return cmd_health_object_common(dl,
|
||||
DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
|
||||
0);
|
||||
}
|
||||
|
||||
static int cmd_health_recover(struct dl *dl)
|
||||
|
@ -57,20 +57,21 @@ void print_nl(void);
|
||||
{ \
|
||||
print_color_##type_name(t, COLOR_NONE, key, fmt, value); \
|
||||
}
|
||||
_PRINT_FUNC(int, int);
|
||||
_PRINT_FUNC(s64, int64_t);
|
||||
_PRINT_FUNC(bool, bool);
|
||||
_PRINT_FUNC(null, const char*);
|
||||
_PRINT_FUNC(string, const char*);
|
||||
_PRINT_FUNC(uint, unsigned int);
|
||||
_PRINT_FUNC(u64, uint64_t);
|
||||
_PRINT_FUNC(hhu, unsigned char);
|
||||
_PRINT_FUNC(hu, unsigned short);
|
||||
_PRINT_FUNC(hex, unsigned int);
|
||||
_PRINT_FUNC(0xhex, unsigned long long);
|
||||
_PRINT_FUNC(luint, unsigned long);
|
||||
_PRINT_FUNC(lluint, unsigned long long);
|
||||
_PRINT_FUNC(float, double);
|
||||
|
||||
_PRINT_FUNC(int, int)
|
||||
_PRINT_FUNC(s64, int64_t)
|
||||
_PRINT_FUNC(bool, bool)
|
||||
_PRINT_FUNC(null, const char*)
|
||||
_PRINT_FUNC(string, const char*)
|
||||
_PRINT_FUNC(uint, unsigned int)
|
||||
_PRINT_FUNC(u64, uint64_t)
|
||||
_PRINT_FUNC(hhu, unsigned char)
|
||||
_PRINT_FUNC(hu, unsigned short)
|
||||
_PRINT_FUNC(hex, unsigned int)
|
||||
_PRINT_FUNC(0xhex, unsigned long long)
|
||||
_PRINT_FUNC(luint, unsigned long)
|
||||
_PRINT_FUNC(lluint, unsigned long long)
|
||||
_PRINT_FUNC(float, double)
|
||||
#undef _PRINT_FUNC
|
||||
|
||||
#endif /* _JSON_PRINT_H_ */
|
||||
|
@ -806,7 +806,7 @@ union bpf_attr {
|
||||
* based on a user-provided identifier for all traffic coming from
|
||||
* the tasks belonging to the related cgroup. See also the related
|
||||
* kernel documentation, available from the Linux sources in file
|
||||
* *Documentation/cgroup-v1/net_cls.txt*.
|
||||
* *Documentation/admin-guide/cgroup-v1/net_cls.rst*.
|
||||
*
|
||||
* The Linux kernel has two versions for cgroups: there are
|
||||
* cgroups v1 and cgroups v2. Both are available to users, who can
|
||||
@ -3248,7 +3248,7 @@ struct bpf_sock_addr {
|
||||
__u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write.
|
||||
* Stored in network byte order.
|
||||
*/
|
||||
__u32 user_ip6[4]; /* Allows 1,2,4-byte read and 4,8-byte write.
|
||||
__u32 user_ip6[4]; /* Allows 1,2,4,8-byte read and 4,8-byte write.
|
||||
* Stored in network byte order.
|
||||
*/
|
||||
__u32 user_port; /* Allows 4-byte read and write.
|
||||
@ -3260,7 +3260,7 @@ struct bpf_sock_addr {
|
||||
__u32 msg_src_ip4; /* Allows 1,2,4-byte read and 4-byte write.
|
||||
* Stored in network byte order.
|
||||
*/
|
||||
__u32 msg_src_ip6[4]; /* Allows 1,2,4-byte read and 4,8-byte write.
|
||||
__u32 msg_src_ip6[4]; /* Allows 1,2,4,8-byte read and 4,8-byte write.
|
||||
* Stored in network byte order.
|
||||
*/
|
||||
__bpf_md_ptr(struct bpf_sock *, sk);
|
||||
|
@ -91,5 +91,7 @@
|
||||
#define UDF_SUPER_MAGIC 0x15013346
|
||||
#define BALLOON_KVM_MAGIC 0x13661366
|
||||
#define ZSMALLOC_MAGIC 0x58295829
|
||||
#define DMA_BUF_MAGIC 0x444d4142 /* "DMAB" */
|
||||
#define Z3FOLD_MAGIC 0x33
|
||||
|
||||
#endif /* __LINUX_MAGIC_H__ */
|
||||
|
@ -1174,7 +1174,7 @@ enum {
|
||||
TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME, /* s64 */
|
||||
TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME_EXTENSION, /* s64 */
|
||||
TCA_TAPRIO_ATTR_FLAGS, /* u32 */
|
||||
TCA_TAPRIO_ATTR_TXTIME_DELAY, /* s32 */
|
||||
TCA_TAPRIO_ATTR_TXTIME_DELAY, /* u32 */
|
||||
__TCA_TAPRIO_ATTR_MAX,
|
||||
};
|
||||
|
||||
|
@ -198,7 +198,7 @@ int nodev(const char *dev);
|
||||
int check_ifname(const char *);
|
||||
int get_ifname(char *, const char *);
|
||||
const char *get_ifname_rta(int ifindex, const struct rtattr *rta);
|
||||
int matches(const char *arg, const char *pattern);
|
||||
bool matches(const char *prefix, const char *string);
|
||||
int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits);
|
||||
int inet_addr_match_rta(const inet_prefix *m, const struct rtattr *rta);
|
||||
|
||||
|
@ -281,8 +281,6 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p)
|
||||
p->link = ll_name_to_index(medium);
|
||||
if (!p->link)
|
||||
return nodev(medium);
|
||||
else
|
||||
strlcpy(p->name, medium, sizeof(p->name));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -371,6 +369,9 @@ static int do_add(int cmd, int argc, char **argv)
|
||||
if (parse_args(argc, argv, cmd, &p) < 0)
|
||||
return -1;
|
||||
|
||||
if (!*p.name)
|
||||
fprintf(stderr, "Tunnel interface name not specified\n");
|
||||
|
||||
if (p.proto == IPPROTO_GRE)
|
||||
basedev = "ip6gre0";
|
||||
else if (p.i_flags & VTI_ISVTI)
|
||||
|
@ -545,7 +545,7 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
||||
|
||||
print_int(PRINT_ANY,
|
||||
"clock",
|
||||
"\n clock %d",
|
||||
"\n clock %d ",
|
||||
clock->freq);
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ static void jsonw_puts(json_writer_t *self, const char *str)
|
||||
fputs("\\b", self->out);
|
||||
break;
|
||||
case '\\':
|
||||
fputs("\\n", self->out);
|
||||
fputs("\\\\", self->out);
|
||||
break;
|
||||
case '"':
|
||||
fputs("\\\"", self->out);
|
||||
|
17
lib/utils.c
17
lib/utils.c
@ -374,7 +374,7 @@ int get_u8(__u8 *val, const char *arg, int base)
|
||||
|
||||
int get_s64(__s64 *val, const char *arg, int base)
|
||||
{
|
||||
long res;
|
||||
long long res;
|
||||
char *ptr;
|
||||
|
||||
errno = 0;
|
||||
@ -871,13 +871,18 @@ const char *get_ifname_rta(int ifindex, const struct rtattr *rta)
|
||||
return name;
|
||||
}
|
||||
|
||||
int matches(const char *cmd, const char *pattern)
|
||||
/* Returns false if 'prefix' is a not empty prefix of 'string'.
|
||||
*/
|
||||
bool matches(const char *prefix, const char *string)
|
||||
{
|
||||
int len = strlen(cmd);
|
||||
if (!*prefix)
|
||||
return true;
|
||||
while (*string && *prefix == *string) {
|
||||
prefix++;
|
||||
string++;
|
||||
}
|
||||
|
||||
if (len > strlen(pattern))
|
||||
return -1;
|
||||
return memcmp(pattern, cmd, len);
|
||||
return !!*prefix;
|
||||
}
|
||||
|
||||
int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits)
|
||||
|
@ -1815,6 +1815,11 @@ can move the system to an unpredictable state. The solution
|
||||
is to avoid changing several parameters with one
|
||||
.B ip link set
|
||||
call.
|
||||
The modifier
|
||||
.B change
|
||||
is equivalent to
|
||||
.BR "set" .
|
||||
|
||||
|
||||
.TP
|
||||
.BI dev " DEVICE "
|
||||
|
@ -34,11 +34,17 @@ rdma-dev \- RDMA device configuration
|
||||
.BR netns
|
||||
.BR NSNAME
|
||||
|
||||
.ti -8
|
||||
.B rdma dev set
|
||||
.RI "[ " DEV " ]"
|
||||
.BR adaptive-moderation
|
||||
.BR [on/off]
|
||||
|
||||
.ti -8
|
||||
.B rdma dev help
|
||||
|
||||
.SH "DESCRIPTION"
|
||||
.SS rdma dev set - rename RDMA device or set network namespace
|
||||
.SS rdma dev set - rename RDMA device or set network namespace or set RDMA device adaptive-moderation
|
||||
|
||||
.SS rdma dev show - display RDMA device attributes
|
||||
|
||||
@ -70,6 +76,14 @@ Changes the network namespace of RDMA device to foo where foo is
|
||||
previously created using iproute2 ip command.
|
||||
.RE
|
||||
.PP
|
||||
rdma dev set mlx5_3 adaptive-moderation [on/off]
|
||||
.RS 4
|
||||
Sets the state of adaptive interrupt moderation for the RDMA device.
|
||||
.RE
|
||||
.RS 4
|
||||
This is a global setting for the RDMA device but the value is printed for each CQ individually because the state is constant from CQ allocation.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR ip (8),
|
||||
@ -77,6 +91,7 @@ previously created using iproute2 ip command.
|
||||
.BR rdma-link (8),
|
||||
.BR rdma-resource (8),
|
||||
.BR rdma-system (8),
|
||||
.BR rdma-statistic (8),
|
||||
.br
|
||||
|
||||
.SH AUTHOR
|
||||
|
@ -97,6 +97,7 @@ Removes RXE link rxe_eth0
|
||||
.BR rdma (8),
|
||||
.BR rdma-dev (8),
|
||||
.BR rdma-resource (8),
|
||||
.BR rdma-statistic (8),
|
||||
.br
|
||||
|
||||
.SH AUTHOR
|
||||
|
@ -103,6 +103,7 @@ Show CQs belonging to pid 30489
|
||||
.BR rdma (8),
|
||||
.BR rdma-dev (8),
|
||||
.BR rdma-link (8),
|
||||
.BR rdma-statistic (8),
|
||||
.br
|
||||
|
||||
.SH AUTHOR
|
||||
|
167
man/man8/rdma-statistic.8
Normal file
167
man/man8/rdma-statistic.8
Normal file
@ -0,0 +1,167 @@
|
||||
.TH RDMA\-STATISTIC 8 "17 Mar 2019" "iproute2" "Linux"
|
||||
.SH NAME
|
||||
rdma-statistic \- RDMA statistic counter configuration
|
||||
.SH SYNOPSIS
|
||||
.sp
|
||||
.ad l
|
||||
.in +8
|
||||
.ti -8
|
||||
.B rdma
|
||||
.RI "[ " OPTIONS " ]"
|
||||
.B statistic
|
||||
.RI " { " COMMAND " | "
|
||||
.BR help " }"
|
||||
.sp
|
||||
|
||||
.ti -8
|
||||
.B rdma statistic
|
||||
.RI "[ " OBJECT " ]"
|
||||
.B show
|
||||
|
||||
.ti -8
|
||||
.B rdma statistic
|
||||
.RI "[ " OBJECT " ]"
|
||||
.B show link
|
||||
.RI "[ " DEV/PORT_INDX " ]"
|
||||
|
||||
.ti -8
|
||||
.B rdma statistic
|
||||
.IR OBJECT
|
||||
.B mode
|
||||
|
||||
.ti -8
|
||||
.B rdma statistic
|
||||
.IR OBJECT
|
||||
.B set
|
||||
.IR COUNTER_SCOPE
|
||||
.RI "[ " DEV/PORT_INDEX "]"
|
||||
.B auto
|
||||
.RI "{ " CRITERIA " | "
|
||||
.BR off " }"
|
||||
|
||||
.ti -8
|
||||
.B rdma statistic
|
||||
.IR OBJECT
|
||||
.B bind
|
||||
.IR COUNTER_SCOPE
|
||||
.RI "[ " DEV/PORT_INDEX "]"
|
||||
.RI "[ " OBJECT-ID " ]"
|
||||
.RI "[ " COUNTER-ID " ]"
|
||||
|
||||
.ti -8
|
||||
.B rdma statistic
|
||||
.IR OBJECT
|
||||
.B unbind
|
||||
.IR COUNTER_SCOPE
|
||||
.RI "[ " DEV/PORT_INDEX "]"
|
||||
.RI "[ " COUNTER-ID " ]"
|
||||
.RI "[ " OBJECT-ID " ]"
|
||||
|
||||
.ti -8
|
||||
.IR COUNTER_SCOPE " := "
|
||||
.RB "{ " link " | " dev " }"
|
||||
|
||||
.ti -8
|
||||
.IR OBJECT " := "
|
||||
.RB "{ " qp " }"
|
||||
|
||||
.ti -8
|
||||
.IR CRITERIA " := "
|
||||
.RB "{ " type " }"
|
||||
|
||||
.SH "DESCRIPTION"
|
||||
.SS rdma statistic [object] show - Queries the specified RDMA device for RDMA and driver-specific statistics. Show the default hw counters if object is not specified
|
||||
|
||||
.PP
|
||||
.I "DEV"
|
||||
- specifies counters on this RDMA device to show.
|
||||
|
||||
.I "PORT_INDEX"
|
||||
- specifies counters on this RDMA port to show.
|
||||
|
||||
.SS rdma statistic <object> set - configure counter statistic auto-mode for a specific device/port
|
||||
In auto mode all objects belong to one category are bind automatically to a single counter set.
|
||||
|
||||
.SS rdma statistic <object> bind - manually bind an object (e.g., a qp) with a counter
|
||||
When bound the statistics of this object are available in this counter.
|
||||
|
||||
.SS rdma statistic <object> unbind - manually unbind an object (e.g., a qp) from the counter previously bound
|
||||
When unbound the statistics of this object are no longer available in this counter; And if object id is not specified then all objects on this counter will be unbound.
|
||||
|
||||
.I "COUNTER-ID"
|
||||
- specifies the id of the counter to be bound.
|
||||
If this argument is omitted then a new counter will be allocated.
|
||||
|
||||
.SH "EXAMPLES"
|
||||
.PP
|
||||
rdma statistic show
|
||||
.RS 4
|
||||
Shows the state of the default counter of all RDMA devices on the system.
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic show link mlx5_2/1
|
||||
.RS 4
|
||||
Shows the state of the default counter of specified RDMA port
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic qp show
|
||||
.RS 4
|
||||
Shows the state of all qp counters of all RDMA devices on the system.
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic qp show link mlx5_2/1
|
||||
.RS 4
|
||||
Shows the state of all qp counters of specified RDMA port.
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic qp show link mlx5_2 pid 30489
|
||||
.RS 4
|
||||
Shows the state of all qp counters of specified RDMA port and belonging to pid 30489
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic qp mode
|
||||
.RS 4
|
||||
List current counter mode on all devices
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic qp mode link mlx5_2/1
|
||||
.RS 4
|
||||
List current counter mode of device mlx5_2 port 1
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic qp set link mlx5_2/1 auto type on
|
||||
.RS 4
|
||||
On device mlx5_2 port 1, for each new QP bind it with a counter automatically. Per counter for QPs with same qp type in each process. Currently only "type" is supported.
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic qp set link mlx5_2/1 auto off
|
||||
.RS 4
|
||||
Turn-off auto mode on device mlx5_2 port 1. The allocated counters can be manually accessed.
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic qp bind link mlx5_2/1 lqpn 178
|
||||
.RS 4
|
||||
On device mlx5_2 port 1, allocate a counter and bind the specified qp on it
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic qp unbind link mlx5_2/1 cntn 4 lqpn 178
|
||||
.RS 4
|
||||
On device mlx5_2 port 1, bind the specified qp on the specified counter
|
||||
.RE
|
||||
.PP
|
||||
rdma statistic qp unbind link mlx5_2/1 cntn 4
|
||||
.RS 4
|
||||
On device mlx5_2 port 1, unbind all QPs on the specified counter. After that this counter will be released automatically by the kernel.
|
||||
|
||||
.RE
|
||||
.PP
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR rdma (8),
|
||||
.BR rdma-dev (8),
|
||||
.BR rdma-link (8),
|
||||
.BR rdma-resource (8),
|
||||
.br
|
||||
|
||||
.SH AUTHOR
|
||||
Mark Zhang <markz@mellanox.com>
|
@ -19,7 +19,7 @@ rdma \- RDMA tool
|
||||
|
||||
.ti -8
|
||||
.IR OBJECT " := { "
|
||||
.BR dev " | " link " | " system " }"
|
||||
.BR dev " | " link " | " system " | " statistic " }"
|
||||
.sp
|
||||
|
||||
.ti -8
|
||||
@ -74,6 +74,10 @@ Generate JSON output.
|
||||
.B sys
|
||||
- RDMA subsystem related.
|
||||
|
||||
.TP
|
||||
.B statistic
|
||||
- RDMA counter statistic related.
|
||||
|
||||
.PP
|
||||
The names of all objects may be written in full or
|
||||
abbreviated form, for example
|
||||
@ -112,6 +116,7 @@ Exit status is 0 if command was successful or a positive integer upon failure.
|
||||
.BR rdma-link (8),
|
||||
.BR rdma-resource (8),
|
||||
.BR rdma-system (8),
|
||||
.BR rdma-statistic (8),
|
||||
.br
|
||||
|
||||
.SH REPORTING BUGS
|
||||
|
@ -2414,7 +2414,7 @@ static void sctp_stats_print(struct sctp_info *s)
|
||||
if (s->sctpi_s_pd_point)
|
||||
out(" pdpoint:%d", s->sctpi_s_pd_point);
|
||||
if (s->sctpi_s_nodelay)
|
||||
out(" nodealy:%d", s->sctpi_s_nodelay);
|
||||
out(" nodelay:%d", s->sctpi_s_nodelay);
|
||||
if (s->sctpi_s_disable_fragments)
|
||||
out(" nofrag:%d", s->sctpi_s_disable_fragments);
|
||||
if (s->sctpi_s_v4mapped)
|
||||
@ -2937,7 +2937,7 @@ static void sctp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
|
||||
len = RTA_PAYLOAD(tb[INET_DIAG_LOCALS]);
|
||||
sa = RTA_DATA(tb[INET_DIAG_LOCALS]);
|
||||
|
||||
out("locals:%s", format_host_sa(sa));
|
||||
out(" locals:%s", format_host_sa(sa));
|
||||
for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa))
|
||||
out(",%s", format_host_sa(sa));
|
||||
|
||||
|
@ -7,7 +7,7 @@ ifeq ($(HAVE_MNL),y)
|
||||
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
|
||||
res-cmid.o res-qp.o sys.o stat.o
|
||||
|
||||
TARGETS += rdma
|
||||
endif
|
||||
|
55
rdma/dev.c
55
rdma/dev.c
@ -12,6 +12,7 @@ static int dev_help(struct rd *rd)
|
||||
pr_out("Usage: %s dev show [DEV]\n", rd->filename);
|
||||
pr_out(" %s dev set [DEV] name DEVNAME\n", rd->filename);
|
||||
pr_out(" %s dev set [DEV] netns NSNAME\n", rd->filename);
|
||||
pr_out(" %s dev set [DEV] adaptive-moderation [on|off]\n", rd->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -167,6 +168,21 @@ static void dev_print_sys_image_guid(struct rd *rd, struct nlattr **tb)
|
||||
pr_out("sys_image_guid %s ", str);
|
||||
}
|
||||
|
||||
static void dev_print_dim_setting(struct rd *rd, struct nlattr **tb)
|
||||
{
|
||||
uint8_t dim_setting;
|
||||
|
||||
if (!tb[RDMA_NLDEV_ATTR_DEV_DIM])
|
||||
return;
|
||||
|
||||
dim_setting = mnl_attr_get_u8(tb[RDMA_NLDEV_ATTR_DEV_DIM]);
|
||||
if (dim_setting > 1)
|
||||
return;
|
||||
|
||||
print_on_off(rd, "adaptive-moderation", dim_setting);
|
||||
|
||||
}
|
||||
|
||||
static const char *node_type_to_str(uint8_t node_type)
|
||||
{
|
||||
static const char * const node_type_str[] = { "unknown", "ca",
|
||||
@ -219,8 +235,10 @@ static int dev_parse_cb(const struct nlmsghdr *nlh, void *data)
|
||||
dev_print_fw(rd, tb);
|
||||
dev_print_node_guid(rd, tb);
|
||||
dev_print_sys_image_guid(rd, tb);
|
||||
if (rd->show_details)
|
||||
if (rd->show_details) {
|
||||
dev_print_dim_setting(rd, tb);
|
||||
dev_print_caps(rd, tb);
|
||||
}
|
||||
|
||||
if (!rd->json_output)
|
||||
pr_out("\n");
|
||||
@ -308,12 +326,47 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dev_set_dim_sendmsg(struct rd *rd, uint8_t dim_setting)
|
||||
{
|
||||
uint32_t seq;
|
||||
|
||||
rd_prepare_msg(rd, RDMA_NLDEV_CMD_SET, &seq,
|
||||
(NLM_F_REQUEST | NLM_F_ACK));
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
|
||||
mnl_attr_put_u8(rd->nlh, RDMA_NLDEV_ATTR_DEV_DIM, dim_setting);
|
||||
|
||||
return rd_sendrecv_msg(rd, seq);
|
||||
}
|
||||
|
||||
static int dev_set_dim_off(struct rd *rd)
|
||||
{
|
||||
return dev_set_dim_sendmsg(rd, 0);
|
||||
}
|
||||
|
||||
static int dev_set_dim_on(struct rd *rd)
|
||||
{
|
||||
return dev_set_dim_sendmsg(rd, 1);
|
||||
}
|
||||
|
||||
static int dev_set_dim(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, dev_help},
|
||||
{ "on", dev_set_dim_on},
|
||||
{ "off", dev_set_dim_off},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
static int dev_one_set(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, dev_help},
|
||||
{ "name", dev_set_name},
|
||||
{ "netns", dev_set_netns},
|
||||
{ "adaptive-moderation", dev_set_dim},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -147,6 +147,18 @@ enum {
|
||||
IWPM_NLA_HELLO_MAX
|
||||
};
|
||||
|
||||
/* For RDMA_NLDEV_ATTR_DEV_NODE_TYPE */
|
||||
enum {
|
||||
/* IB values map to NodeInfo:NodeType. */
|
||||
RDMA_NODE_IB_CA = 1,
|
||||
RDMA_NODE_IB_SWITCH,
|
||||
RDMA_NODE_IB_ROUTER,
|
||||
RDMA_NODE_RNIC,
|
||||
RDMA_NODE_USNIC,
|
||||
RDMA_NODE_USNIC_UDP,
|
||||
RDMA_NODE_UNSPECIFIED,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local service operations:
|
||||
* RESOLVE - The client requests the local service to resolve a path.
|
||||
@ -267,11 +279,15 @@ enum rdma_nldev_command {
|
||||
|
||||
RDMA_NLDEV_CMD_RES_PD_GET, /* can dump */
|
||||
|
||||
RDMA_NLDEV_NUM_OPS
|
||||
};
|
||||
RDMA_NLDEV_CMD_GET_CHARDEV,
|
||||
|
||||
enum {
|
||||
RDMA_NLDEV_ATTR_ENTRY_STRLEN = 16,
|
||||
RDMA_NLDEV_CMD_STAT_SET,
|
||||
|
||||
RDMA_NLDEV_CMD_STAT_GET, /* can dump */
|
||||
|
||||
RDMA_NLDEV_CMD_STAT_DEL,
|
||||
|
||||
RDMA_NLDEV_NUM_OPS
|
||||
};
|
||||
|
||||
enum rdma_nldev_print_type {
|
||||
@ -478,10 +494,72 @@ enum rdma_nldev_attr {
|
||||
* File descriptor handle of the net namespace object
|
||||
*/
|
||||
RDMA_NLDEV_NET_NS_FD, /* u32 */
|
||||
/*
|
||||
* Information about a chardev.
|
||||
* CHARDEV_TYPE is the name of the chardev ABI (ie uverbs, umad, etc)
|
||||
* CHARDEV_ABI signals the ABI revision (historical)
|
||||
* CHARDEV_NAME is the kernel name for the /dev/ file (no directory)
|
||||
* CHARDEV is the 64 bit dev_t for the inode
|
||||
*/
|
||||
RDMA_NLDEV_ATTR_CHARDEV_TYPE, /* string */
|
||||
RDMA_NLDEV_ATTR_CHARDEV_NAME, /* string */
|
||||
RDMA_NLDEV_ATTR_CHARDEV_ABI, /* u64 */
|
||||
RDMA_NLDEV_ATTR_CHARDEV, /* u64 */
|
||||
RDMA_NLDEV_ATTR_UVERBS_DRIVER_ID, /* u64 */
|
||||
/*
|
||||
* Counter-specific attributes.
|
||||
*/
|
||||
RDMA_NLDEV_ATTR_STAT_MODE, /* u32 */
|
||||
RDMA_NLDEV_ATTR_STAT_RES, /* u32 */
|
||||
RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK, /* u32 */
|
||||
RDMA_NLDEV_ATTR_STAT_COUNTER, /* nested table */
|
||||
RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY, /* nested table */
|
||||
RDMA_NLDEV_ATTR_STAT_COUNTER_ID, /* u32 */
|
||||
RDMA_NLDEV_ATTR_STAT_HWCOUNTERS, /* nested table */
|
||||
RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY, /* nested table */
|
||||
RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME, /* string */
|
||||
RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE, /* u64 */
|
||||
|
||||
/*
|
||||
* CQ adaptive moderatio (DIM)
|
||||
*/
|
||||
RDMA_NLDEV_ATTR_DEV_DIM, /* u8 */
|
||||
|
||||
/*
|
||||
* Always the end
|
||||
*/
|
||||
RDMA_NLDEV_ATTR_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* Supported counter bind modes. All modes are mutual-exclusive.
|
||||
*/
|
||||
enum rdma_nl_counter_mode {
|
||||
RDMA_COUNTER_MODE_NONE,
|
||||
|
||||
/*
|
||||
* A qp is bound with a counter automatically during initialization
|
||||
* based on the auto mode (e.g., qp type, ...)
|
||||
*/
|
||||
RDMA_COUNTER_MODE_AUTO,
|
||||
|
||||
/*
|
||||
* Which qp are bound with which counter is explicitly specified
|
||||
* by the user
|
||||
*/
|
||||
RDMA_COUNTER_MODE_MANUAL,
|
||||
|
||||
/*
|
||||
* Always the end
|
||||
*/
|
||||
RDMA_COUNTER_MODE_MAX,
|
||||
};
|
||||
|
||||
/*
|
||||
* Supported criteria in counter auto mode.
|
||||
* Currently only "qp type" is supported
|
||||
*/
|
||||
enum rdma_nl_counter_mask {
|
||||
RDMA_COUNTER_MASK_QP_TYPE = 1,
|
||||
};
|
||||
#endif /* _RDMA_NETLINK_H */
|
||||
|
@ -11,7 +11,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 | help }\n"
|
||||
"where OBJECT := { dev | link | resource | system | statistic | help }\n"
|
||||
" OPTIONS := { -V[ersion] | -d[etails] | -j[son] | -p[retty]}\n", name, name);
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ static int rd_cmd(struct rd *rd, int argc, char **argv)
|
||||
{ "link", cmd_link },
|
||||
{ "resource", cmd_res },
|
||||
{ "system", cmd_sys },
|
||||
{ "statistic", cmd_stat },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -94,6 +94,7 @@ int cmd_dev(struct rd *rd);
|
||||
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 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));
|
||||
@ -135,6 +136,7 @@ int rd_attr_check(const struct nlattr *attr, int *typep);
|
||||
void print_driver_table(struct rd *rd, struct nlattr *tb);
|
||||
void newline(struct rd *rd);
|
||||
void newline_indent(struct rd *rd);
|
||||
void print_on_off(struct rd *rd, const char *key_str, bool on);
|
||||
#define MAX_LINE_LENGTH 80
|
||||
|
||||
#endif /* _RDMA_TOOL_H_ */
|
||||
|
@ -30,6 +30,20 @@ static void print_poll_ctx(struct rd *rd, uint8_t poll_ctx, struct nlattr *attr)
|
||||
pr_out("poll-ctx %s ", poll_ctx_to_str(poll_ctx));
|
||||
}
|
||||
|
||||
static void print_cq_dim_setting(struct rd *rd, struct nlattr *attr)
|
||||
{
|
||||
uint8_t dim_setting;
|
||||
|
||||
if (!attr)
|
||||
return;
|
||||
|
||||
dim_setting = mnl_attr_get_u8(attr);
|
||||
if (dim_setting > 1)
|
||||
return;
|
||||
|
||||
print_on_off(rd, "adaptive-moderation", dim_setting);
|
||||
}
|
||||
|
||||
static int res_cq_line(struct rd *rd, const char *name, int idx,
|
||||
struct nlattr **nla_line)
|
||||
{
|
||||
@ -97,6 +111,7 @@ static int res_cq_line(struct rd *rd, const char *name, int idx,
|
||||
res_print_uint(rd, "users", users,
|
||||
nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
|
||||
print_poll_ctx(rd, poll_ctx, nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]);
|
||||
print_cq_dim_setting(rd, nla_line[RDMA_NLDEV_ATTR_DEV_DIM]);
|
||||
res_print_uint(rd, "ctxn", ctxn, nla_line[RDMA_NLDEV_ATTR_RES_CTXN]);
|
||||
res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
|
||||
print_comm(rd, comm, nla_line);
|
||||
|
759
rdma/stat.c
Normal file
759
rdma/stat.c
Normal file
@ -0,0 +1,759 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
||||
/*
|
||||
* rdma.c RDMA tool
|
||||
* Authors: Mark Zhang <markz@mellanox.com>
|
||||
*/
|
||||
|
||||
#include "rdma.h"
|
||||
#include "res.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
static int stat_help(struct rd *rd)
|
||||
{
|
||||
pr_out("Usage: %s [ OPTIONS ] statistic { COMMAND | help }\n", rd->filename);
|
||||
pr_out(" %s statistic OBJECT show\n", rd->filename);
|
||||
pr_out(" %s statistic OBJECT show link [ DEV/PORT_INDEX ] [ FILTER-NAME FILTER-VALUE ]\n", rd->filename);
|
||||
pr_out(" %s statistic OBJECT mode\n", rd->filename);
|
||||
pr_out(" %s statistic OBJECT set COUNTER_SCOPE [DEV/PORT_INDEX] auto {CRITERIA | off}\n", rd->filename);
|
||||
pr_out(" %s statistic OBJECT bind COUNTER_SCOPE [DEV/PORT_INDEX] [OBJECT-ID] [COUNTER-ID]\n", rd->filename);
|
||||
pr_out(" %s statistic OBJECT unbind COUNTER_SCOPE [DEV/PORT_INDEX] [COUNTER-ID]\n", rd->filename);
|
||||
pr_out(" %s statistic show\n", rd->filename);
|
||||
pr_out(" %s statistic show link [ DEV/PORT_INDEX ]\n", rd->filename);
|
||||
pr_out("where OBJECT: = { qp }\n");
|
||||
pr_out(" CRITERIA : = { type }\n");
|
||||
pr_out(" COUNTER_SCOPE: = { link | dev }\n");
|
||||
pr_out("Examples:\n");
|
||||
pr_out(" %s statistic qp show\n", rd->filename);
|
||||
pr_out(" %s statistic qp show link mlx5_2/1\n", rd->filename);
|
||||
pr_out(" %s statistic qp mode\n", rd->filename);
|
||||
pr_out(" %s statistic qp mode link mlx5_0\n", rd->filename);
|
||||
pr_out(" %s statistic qp set link mlx5_2/1 auto type on\n", rd->filename);
|
||||
pr_out(" %s statistic qp set link mlx5_2/1 auto off\n", rd->filename);
|
||||
pr_out(" %s statistic qp bind link mlx5_2/1 lqpn 178\n", rd->filename);
|
||||
pr_out(" %s statistic qp bind link mlx5_2/1 lqpn 178 cntn 4\n", rd->filename);
|
||||
pr_out(" %s statistic qp unbind link mlx5_2/1 cntn 4\n", rd->filename);
|
||||
pr_out(" %s statistic qp unbind link mlx5_2/1 cntn 4 lqpn 178\n", rd->filename);
|
||||
pr_out(" %s statistic show\n", rd->filename);
|
||||
pr_out(" %s statistic show link mlx5_2/1\n", rd->filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct counter_param {
|
||||
char *name;
|
||||
uint32_t attr;
|
||||
};
|
||||
|
||||
static struct counter_param auto_params[] = {
|
||||
{ "type", RDMA_COUNTER_MASK_QP_TYPE, },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static int prepare_auto_mode_str(struct nlattr **tb, uint32_t mask,
|
||||
char *output, int len)
|
||||
{
|
||||
char s[] = "qp auto";
|
||||
int i, outlen = strlen(s);
|
||||
|
||||
memset(output, 0, len);
|
||||
snprintf(output, len, "%s", s);
|
||||
|
||||
if (mask) {
|
||||
for (i = 0; auto_params[i].name != NULL; i++) {
|
||||
if (mask & auto_params[i].attr) {
|
||||
outlen += strlen(auto_params[i].name) + 1;
|
||||
if (outlen >= len)
|
||||
return -EINVAL;
|
||||
strcat(output, " ");
|
||||
strcat(output, auto_params[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
if (outlen + strlen(" on") >= len)
|
||||
return -EINVAL;
|
||||
strcat(output, " on");
|
||||
} else {
|
||||
if (outlen + strlen(" off") >= len)
|
||||
return -EINVAL;
|
||||
strcat(output, " off");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qp_link_get_mode_parse_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
|
||||
uint32_t mode = 0, mask = 0;
|
||||
char output[128] = {};
|
||||
struct rd *rd = data;
|
||||
uint32_t idx, port;
|
||||
const char *name;
|
||||
|
||||
mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
|
||||
if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
if (!tb[RDMA_NLDEV_ATTR_PORT_INDEX]) {
|
||||
pr_err("This tool doesn't support switches yet\n");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
|
||||
port = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
|
||||
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
|
||||
if (tb[RDMA_NLDEV_ATTR_STAT_MODE])
|
||||
mode = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_STAT_MODE]);
|
||||
|
||||
if (mode == RDMA_COUNTER_MODE_AUTO) {
|
||||
if (!tb[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK])
|
||||
return MNL_CB_ERROR;
|
||||
mask = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK]);
|
||||
prepare_auto_mode_str(tb, mask, output, sizeof(output));
|
||||
} else {
|
||||
snprintf(output, sizeof(output), "qp auto off");
|
||||
}
|
||||
|
||||
if (rd->json_output) {
|
||||
jsonw_uint_field(rd->jw, "ifindex", idx);
|
||||
jsonw_uint_field(rd->jw, "port", port);
|
||||
jsonw_string_field(rd->jw, "mode", output);
|
||||
} else {
|
||||
pr_out("%u/%u: %s/%u: %s\n", idx, port, name, port, output);
|
||||
}
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int stat_one_qp_link_get_mode(struct rd *rd)
|
||||
{
|
||||
uint32_t seq;
|
||||
int ret;
|
||||
|
||||
if (!rd->port_idx)
|
||||
return 0;
|
||||
|
||||
rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_GET,
|
||||
&seq, (NLM_F_REQUEST | NLM_F_ACK));
|
||||
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
|
||||
/* Make RDMA_NLDEV_ATTR_STAT_MODE valid so that kernel knows
|
||||
* return only mode instead of all counters
|
||||
*/
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_MODE,
|
||||
RDMA_COUNTER_MODE_MANUAL);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
|
||||
ret = rd_send_msg(rd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rd->json_output)
|
||||
jsonw_start_object(rd->jw);
|
||||
ret = rd_recv_msg(rd, qp_link_get_mode_parse_cb, rd, seq);
|
||||
if (rd->json_output)
|
||||
jsonw_end_object(rd->jw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stat_qp_link_get_mode(struct rd *rd)
|
||||
{
|
||||
return rd_exec_link(rd, stat_one_qp_link_get_mode, false);
|
||||
}
|
||||
|
||||
static int stat_qp_get_mode(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_qp_link_get_mode },
|
||||
{ "link", stat_qp_link_get_mode },
|
||||
{ "help", stat_help },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
static int res_get_hwcounters(struct rd *rd, struct nlattr *hwc_table, bool print)
|
||||
{
|
||||
struct nlattr *nla_entry;
|
||||
const char *nm;
|
||||
uint64_t v;
|
||||
int err;
|
||||
|
||||
mnl_attr_for_each_nested(nla_entry, hwc_table) {
|
||||
struct nlattr *hw_line[RDMA_NLDEV_ATTR_MAX] = {};
|
||||
|
||||
err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, hw_line);
|
||||
if (err != MNL_CB_OK)
|
||||
return -EINVAL;
|
||||
|
||||
if (!hw_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME] ||
|
||||
!hw_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE]) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!print)
|
||||
continue;
|
||||
|
||||
nm = mnl_attr_get_str(hw_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME]);
|
||||
v = mnl_attr_get_u64(hw_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE]);
|
||||
if (rd->pretty_output && !rd->json_output)
|
||||
newline_indent(rd);
|
||||
res_print_uint(rd, nm, v, hw_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME]);
|
||||
}
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int res_counter_line(struct rd *rd, const char *name, int index,
|
||||
struct nlattr **nla_line)
|
||||
{
|
||||
uint32_t cntn, port = 0, pid = 0, qpn;
|
||||
struct nlattr *hwc_table, *qp_table;
|
||||
struct nlattr *nla_entry;
|
||||
const char *comm = NULL;
|
||||
bool isfirst;
|
||||
int err;
|
||||
|
||||
if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
|
||||
port = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
|
||||
|
||||
hwc_table = nla_line[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS];
|
||||
qp_table = nla_line[RDMA_NLDEV_ATTR_RES_QP];
|
||||
if (!hwc_table || !qp_table ||
|
||||
!nla_line[RDMA_NLDEV_ATTR_STAT_COUNTER_ID])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
cntn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]);
|
||||
if (rd_is_filtered_attr(rd, "cntn", cntn,
|
||||
nla_line[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]))
|
||||
return MNL_CB_OK;
|
||||
|
||||
if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) {
|
||||
pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]);
|
||||
comm = get_task_name(pid);
|
||||
}
|
||||
if (rd_is_filtered_attr(rd, "pid", pid,
|
||||
nla_line[RDMA_NLDEV_ATTR_RES_PID]))
|
||||
return MNL_CB_OK;
|
||||
|
||||
if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
|
||||
comm = (char *)mnl_attr_get_str(
|
||||
nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
|
||||
|
||||
mnl_attr_for_each_nested(nla_entry, qp_table) {
|
||||
struct nlattr *qp_line[RDMA_NLDEV_ATTR_MAX] = {};
|
||||
|
||||
err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, qp_line);
|
||||
if (err != MNL_CB_OK)
|
||||
return -EINVAL;
|
||||
|
||||
if (!qp_line[RDMA_NLDEV_ATTR_RES_LQPN])
|
||||
return -EINVAL;
|
||||
|
||||
qpn = mnl_attr_get_u32(qp_line[RDMA_NLDEV_ATTR_RES_LQPN]);
|
||||
if (rd_is_filtered_attr(rd, "lqpn", qpn,
|
||||
qp_line[RDMA_NLDEV_ATTR_RES_LQPN]))
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
err = res_get_hwcounters(rd, hwc_table, false);
|
||||
if (err != MNL_CB_OK)
|
||||
return err;
|
||||
|
||||
if (rd->json_output) {
|
||||
jsonw_string_field(rd->jw, "ifname", name);
|
||||
if (port)
|
||||
jsonw_uint_field(rd->jw, "port", port);
|
||||
jsonw_uint_field(rd->jw, "cntn", cntn);
|
||||
} else {
|
||||
if (port)
|
||||
pr_out("link %s/%u cntn %u ", name, port, cntn);
|
||||
else
|
||||
pr_out("dev %s cntn %u ", name, cntn);
|
||||
}
|
||||
|
||||
res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
|
||||
print_comm(rd, comm, nla_line);
|
||||
|
||||
res_get_hwcounters(rd, hwc_table, true);
|
||||
|
||||
isfirst = true;
|
||||
mnl_attr_for_each_nested(nla_entry, qp_table) {
|
||||
struct nlattr *qp_line[RDMA_NLDEV_ATTR_MAX] = {};
|
||||
|
||||
if (isfirst && !rd->json_output)
|
||||
pr_out("\n LQPN: <");
|
||||
|
||||
err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, qp_line);
|
||||
if (err != MNL_CB_OK)
|
||||
return -EINVAL;
|
||||
|
||||
if (!qp_line[RDMA_NLDEV_ATTR_RES_LQPN])
|
||||
return -EINVAL;
|
||||
|
||||
qpn = mnl_attr_get_u32(qp_line[RDMA_NLDEV_ATTR_RES_LQPN]);
|
||||
if (rd->json_output) {
|
||||
jsonw_uint_field(rd->jw, "lqpn", qpn);
|
||||
} else {
|
||||
if (isfirst)
|
||||
pr_out("%d", qpn);
|
||||
else
|
||||
pr_out(", %d", qpn);
|
||||
}
|
||||
isfirst = false;
|
||||
}
|
||||
|
||||
if (!rd->json_output)
|
||||
pr_out(">\n");
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int stat_qp_show_parse_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
|
||||
struct nlattr *nla_table, *nla_entry;
|
||||
struct rd *rd = data;
|
||||
const char *name;
|
||||
uint32_t idx;
|
||||
int ret;
|
||||
|
||||
mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
|
||||
if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
|
||||
!tb[RDMA_NLDEV_ATTR_STAT_COUNTER])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
|
||||
idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
|
||||
nla_table = tb[RDMA_NLDEV_ATTR_STAT_COUNTER];
|
||||
|
||||
mnl_attr_for_each_nested(nla_entry, nla_table) {
|
||||
struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
|
||||
|
||||
ret = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
|
||||
if (ret != MNL_CB_OK)
|
||||
break;
|
||||
|
||||
ret = res_counter_line(rd, name, idx, nla_line);
|
||||
if (ret != MNL_CB_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct filters stat_valid_filters[MAX_NUMBER_OF_FILTERS] = {
|
||||
{ .name = "cntn", .is_number = true },
|
||||
{ .name = "lqpn", .is_number = true },
|
||||
{ .name = "pid", .is_number = true },
|
||||
};
|
||||
|
||||
static int stat_qp_show_one_link(struct rd *rd)
|
||||
{
|
||||
int flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
|
||||
uint32_t seq;
|
||||
int ret;
|
||||
|
||||
if (!rd->port_idx)
|
||||
return 0;
|
||||
|
||||
ret = rd_build_filter(rd, stat_valid_filters);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_GET, &seq, flags);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
|
||||
ret = rd_send_msg(rd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rd->json_output)
|
||||
jsonw_start_object(rd->jw);
|
||||
ret = rd_recv_msg(rd, stat_qp_show_parse_cb, rd, seq);
|
||||
if (rd->json_output)
|
||||
jsonw_end_object(rd->jw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stat_qp_show_link(struct rd *rd)
|
||||
{
|
||||
return rd_exec_link(rd, stat_qp_show_one_link, false);
|
||||
}
|
||||
|
||||
static int stat_qp_show(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_qp_show_link },
|
||||
{ "link", stat_qp_show_link },
|
||||
{ "help", stat_help },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
static int stat_qp_set_link_auto_sendmsg(struct rd *rd, uint32_t mask)
|
||||
{
|
||||
uint32_t seq;
|
||||
|
||||
rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_SET,
|
||||
&seq, (NLM_F_REQUEST | NLM_F_ACK));
|
||||
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_MODE,
|
||||
RDMA_COUNTER_MODE_AUTO);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK, mask);
|
||||
|
||||
return rd_sendrecv_msg(rd, seq);
|
||||
}
|
||||
|
||||
static int stat_one_qp_set_link_auto_off(struct rd *rd)
|
||||
{
|
||||
return stat_qp_set_link_auto_sendmsg(rd, 0);
|
||||
}
|
||||
|
||||
static int stat_one_qp_set_auto_type_on(struct rd *rd)
|
||||
{
|
||||
return stat_qp_set_link_auto_sendmsg(rd, RDMA_COUNTER_MASK_QP_TYPE);
|
||||
}
|
||||
|
||||
static int stat_one_qp_set_link_auto_type(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_help },
|
||||
{ "on", stat_one_qp_set_auto_type_on },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
static int stat_one_qp_set_link_auto(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_one_qp_link_get_mode },
|
||||
{ "off", stat_one_qp_set_link_auto_off },
|
||||
{ "type", stat_one_qp_set_link_auto_type },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
static int stat_one_qp_set_link(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_one_qp_link_get_mode },
|
||||
{ "auto", stat_one_qp_set_link_auto },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
if (!rd->port_idx)
|
||||
return 0;
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
static int stat_qp_set_link(struct rd *rd)
|
||||
{
|
||||
return rd_exec_link(rd, stat_one_qp_set_link, false);
|
||||
}
|
||||
|
||||
static int stat_qp_set(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_help },
|
||||
{ "link", stat_qp_set_link },
|
||||
{ "help", stat_help },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
static int stat_get_arg(struct rd *rd, const char *arg)
|
||||
{
|
||||
int value = 0;
|
||||
char *endp;
|
||||
|
||||
if (strcmpx(rd_argv(rd), arg) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
rd_arg_inc(rd);
|
||||
value = strtol(rd_argv(rd), &endp, 10);
|
||||
rd_arg_inc(rd);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int stat_one_qp_bind(struct rd *rd)
|
||||
{
|
||||
int lqpn = 0, cntn = 0, ret;
|
||||
uint32_t seq;
|
||||
|
||||
if (rd_no_arg(rd)) {
|
||||
stat_help(rd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = rd_build_filter(rd, stat_valid_filters);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
lqpn = stat_get_arg(rd, "lqpn");
|
||||
|
||||
rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_SET,
|
||||
&seq, (NLM_F_REQUEST | NLM_F_ACK));
|
||||
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_MODE,
|
||||
RDMA_COUNTER_MODE_MANUAL);
|
||||
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_RES_LQPN, lqpn);
|
||||
|
||||
if (rd_argc(rd)) {
|
||||
cntn = stat_get_arg(rd, "cntn");
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_COUNTER_ID,
|
||||
cntn);
|
||||
}
|
||||
|
||||
return rd_sendrecv_msg(rd, seq);
|
||||
}
|
||||
|
||||
static int do_stat_qp_unbind_lqpn(struct rd *rd, uint32_t cntn, uint32_t lqpn)
|
||||
{
|
||||
uint32_t seq;
|
||||
|
||||
rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_DEL,
|
||||
&seq, (NLM_F_REQUEST | NLM_F_ACK));
|
||||
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_MODE,
|
||||
RDMA_COUNTER_MODE_MANUAL);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, cntn);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_RES_LQPN, lqpn);
|
||||
|
||||
return rd_sendrecv_msg(rd, seq);
|
||||
}
|
||||
|
||||
static int stat_get_counter_parse_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
|
||||
struct nlattr *nla_table, *nla_entry;
|
||||
struct rd *rd = data;
|
||||
uint32_t lqpn, cntn;
|
||||
int err;
|
||||
|
||||
mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
|
||||
|
||||
if (!tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID])
|
||||
return MNL_CB_ERROR;
|
||||
cntn = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]);
|
||||
|
||||
nla_table = tb[RDMA_NLDEV_ATTR_RES_QP];
|
||||
if (!nla_table)
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
mnl_attr_for_each_nested(nla_entry, nla_table) {
|
||||
struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {};
|
||||
|
||||
err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line);
|
||||
if (err != MNL_CB_OK)
|
||||
return -EINVAL;
|
||||
|
||||
if (!nla_line[RDMA_NLDEV_ATTR_RES_LQPN])
|
||||
return -EINVAL;
|
||||
|
||||
lqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
|
||||
err = do_stat_qp_unbind_lqpn(rd, cntn, lqpn);
|
||||
if (err)
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int stat_one_qp_unbind(struct rd *rd)
|
||||
{
|
||||
int flags = NLM_F_REQUEST | NLM_F_ACK, ret;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
int lqpn = 0, cntn = 0;
|
||||
unsigned int portid;
|
||||
uint32_t seq;
|
||||
|
||||
ret = rd_build_filter(rd, stat_valid_filters);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cntn = stat_get_arg(rd, "cntn");
|
||||
if (rd_argc(rd)) {
|
||||
lqpn = stat_get_arg(rd, "lqpn");
|
||||
return do_stat_qp_unbind_lqpn(rd, cntn, lqpn);
|
||||
}
|
||||
|
||||
rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_GET, &seq, flags);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_RES, RDMA_NLDEV_ATTR_RES_QP);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_STAT_COUNTER_ID, cntn);
|
||||
ret = rd_send_msg(rd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
/* Can't use rd_recv_msg() since the callback also calls it (recursively),
|
||||
* then rd_recv_msg() always return -1 here
|
||||
*/
|
||||
portid = mnl_socket_get_portid(rd->nl);
|
||||
ret = mnl_socket_recvfrom(rd->nl, buf, sizeof(buf));
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
ret = mnl_cb_run(buf, ret, seq, portid, stat_get_counter_parse_cb, rd);
|
||||
mnl_socket_close(rd->nl);
|
||||
if (ret != MNL_CB_OK)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stat_qp_bind_link(struct rd *rd)
|
||||
{
|
||||
return rd_exec_link(rd, stat_one_qp_bind, true);
|
||||
}
|
||||
|
||||
static int stat_qp_bind(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_help },
|
||||
{ "link", stat_qp_bind_link },
|
||||
{ "help", stat_help },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
static int stat_qp_unbind_link(struct rd *rd)
|
||||
{
|
||||
return rd_exec_link(rd, stat_one_qp_unbind, true);
|
||||
}
|
||||
|
||||
static int stat_qp_unbind(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_help },
|
||||
{ "link", stat_qp_unbind_link },
|
||||
{ "help", stat_help },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
static int stat_qp(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_qp_show },
|
||||
{ "show", stat_qp_show },
|
||||
{ "list", stat_qp_show },
|
||||
{ "mode", stat_qp_get_mode },
|
||||
{ "set", stat_qp_set },
|
||||
{ "bind", stat_qp_bind },
|
||||
{ "unbind", stat_qp_unbind },
|
||||
{ "help", stat_help },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
static int stat_show_parse_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
|
||||
struct rd *rd = data;
|
||||
const char *name;
|
||||
uint32_t port;
|
||||
int ret;
|
||||
|
||||
mnl_attr_parse(nlh, 0, rd_attr_cb, tb);
|
||||
if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || !tb[RDMA_NLDEV_ATTR_DEV_NAME] ||
|
||||
!tb[RDMA_NLDEV_ATTR_PORT_INDEX] ||
|
||||
!tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
|
||||
port = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_PORT_INDEX]);
|
||||
if (rd->json_output) {
|
||||
jsonw_string_field(rd->jw, "ifname", name);
|
||||
jsonw_uint_field(rd->jw, "port", port);
|
||||
} else {
|
||||
pr_out("link %s/%u ", name, port);
|
||||
}
|
||||
|
||||
ret = res_get_hwcounters(rd, tb[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS], true);
|
||||
|
||||
if (!rd->json_output)
|
||||
pr_out("\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stat_show_one_link(struct rd *rd)
|
||||
{
|
||||
int flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
uint32_t seq;
|
||||
int ret;
|
||||
|
||||
if (!rd->port_idx)
|
||||
return 0;
|
||||
|
||||
rd_prepare_msg(rd, RDMA_NLDEV_CMD_STAT_GET, &seq, flags);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx);
|
||||
mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx);
|
||||
ret = rd_send_msg(rd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return rd_recv_msg(rd, stat_show_parse_cb, rd, seq);
|
||||
}
|
||||
|
||||
static int stat_show_link(struct rd *rd)
|
||||
{
|
||||
return rd_exec_link(rd, stat_show_one_link, false);
|
||||
}
|
||||
|
||||
static int stat_show(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_show_link },
|
||||
{ "link", stat_show_link },
|
||||
{ "help", stat_help },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "parameter");
|
||||
}
|
||||
|
||||
int cmd_stat(struct rd *rd)
|
||||
{
|
||||
const struct rd_cmd cmds[] = {
|
||||
{ NULL, stat_show },
|
||||
{ "show", stat_show },
|
||||
{ "list", stat_show },
|
||||
{ "help", stat_help },
|
||||
{ "qp", stat_qp },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
return rd_exec_cmd(rd, cmds, "statistic command");
|
||||
}
|
23
rdma/utils.c
23
rdma/utils.c
@ -56,7 +56,7 @@ bool rd_no_arg(struct rd *rd)
|
||||
* mlx5_1/1 | 1 | false
|
||||
* mlx5_1/- | 0 | false
|
||||
*
|
||||
* In strict mode, /- will return error.
|
||||
* In strict port mode, a non-0 port must be provided
|
||||
*/
|
||||
static int get_port_from_argv(struct rd *rd, uint32_t *port,
|
||||
bool *is_dump_all, bool strict_port)
|
||||
@ -64,7 +64,7 @@ static int get_port_from_argv(struct rd *rd, uint32_t *port,
|
||||
char *slash;
|
||||
|
||||
*port = 0;
|
||||
*is_dump_all = true;
|
||||
*is_dump_all = strict_port ? false : true;
|
||||
|
||||
slash = strchr(rd_argv(rd), '/');
|
||||
/* if no port found, return 0 */
|
||||
@ -83,6 +83,9 @@ static int get_port_from_argv(struct rd *rd, uint32_t *port,
|
||||
if (!*port && strlen(slash))
|
||||
return -EINVAL;
|
||||
}
|
||||
if (strict_port && (*port == 0))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -436,6 +439,17 @@ static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = {
|
||||
[RDMA_NLDEV_ATTR_DRIVER_S64] = MNL_TYPE_U64,
|
||||
[RDMA_NLDEV_ATTR_DRIVER_U64] = MNL_TYPE_U64,
|
||||
[RDMA_NLDEV_SYS_ATTR_NETNS_MODE] = MNL_TYPE_U8,
|
||||
[RDMA_NLDEV_ATTR_STAT_COUNTER] = MNL_TYPE_NESTED,
|
||||
[RDMA_NLDEV_ATTR_STAT_COUNTER_ENTRY] = MNL_TYPE_NESTED,
|
||||
[RDMA_NLDEV_ATTR_STAT_COUNTER_ID] = MNL_TYPE_U32,
|
||||
[RDMA_NLDEV_ATTR_STAT_HWCOUNTERS] = MNL_TYPE_NESTED,
|
||||
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY] = MNL_TYPE_NESTED,
|
||||
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_NAME] = MNL_TYPE_NUL_STRING,
|
||||
[RDMA_NLDEV_ATTR_STAT_HWCOUNTER_ENTRY_VALUE] = MNL_TYPE_U64,
|
||||
[RDMA_NLDEV_ATTR_STAT_MODE] = MNL_TYPE_U32,
|
||||
[RDMA_NLDEV_ATTR_STAT_RES] = MNL_TYPE_U32,
|
||||
[RDMA_NLDEV_ATTR_STAT_AUTO_MODE_MASK] = MNL_TYPE_U32,
|
||||
[RDMA_NLDEV_ATTR_DEV_DIM] = MNL_TYPE_U8,
|
||||
};
|
||||
|
||||
int rd_attr_check(const struct nlattr *attr, int *typep)
|
||||
@ -776,6 +790,11 @@ static int print_driver_string(struct rd *rd, const char *key_str,
|
||||
}
|
||||
}
|
||||
|
||||
void print_on_off(struct rd *rd, const char *key_str, bool on)
|
||||
{
|
||||
print_driver_string(rd, key_str, (on) ? "on":"off");
|
||||
}
|
||||
|
||||
static int print_driver_s32(struct rd *rd, const char *key_str, int32_t val,
|
||||
enum rdma_nldev_print_type print_type)
|
||||
{
|
||||
|
@ -557,61 +557,40 @@ bad_val:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct tc_action_req {
|
||||
struct nlmsghdr n;
|
||||
struct tcamsg t;
|
||||
char buf[MAX_MSG];
|
||||
};
|
||||
|
||||
static int tc_action_modify(int cmd, unsigned int flags,
|
||||
int *argc_p, char ***argv_p,
|
||||
void *buf, size_t buflen)
|
||||
int *argc_p, char ***argv_p)
|
||||
{
|
||||
struct tc_action_req *req, action_req;
|
||||
char **argv = *argv_p;
|
||||
struct rtattr *tail;
|
||||
int argc = *argc_p;
|
||||
struct iovec iov;
|
||||
char **argv = *argv_p;
|
||||
int ret = 0;
|
||||
|
||||
if (buf) {
|
||||
req = buf;
|
||||
if (buflen < sizeof (struct tc_action_req)) {
|
||||
fprintf(stderr, "buffer is too small: %zu\n", buflen);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
memset(&action_req, 0, sizeof (struct tc_action_req));
|
||||
req = &action_req;
|
||||
}
|
||||
|
||||
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg));
|
||||
req->n.nlmsg_flags = NLM_F_REQUEST | flags;
|
||||
req->n.nlmsg_type = cmd;
|
||||
req->t.tca_family = AF_UNSPEC;
|
||||
tail = NLMSG_TAIL(&req->n);
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct tcamsg t;
|
||||
char buf[MAX_MSG];
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST | flags,
|
||||
.n.nlmsg_type = cmd,
|
||||
.t.tca_family = AF_UNSPEC,
|
||||
};
|
||||
struct rtattr *tail = NLMSG_TAIL(&req.n);
|
||||
|
||||
argc -= 1;
|
||||
argv += 1;
|
||||
if (parse_action(&argc, &argv, TCA_ACT_TAB, &req->n)) {
|
||||
if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) {
|
||||
fprintf(stderr, "Illegal \"action\"\n");
|
||||
return -1;
|
||||
}
|
||||
tail->rta_len = (void *) NLMSG_TAIL(&req->n) - (void *) tail;
|
||||
tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
|
||||
|
||||
*argc_p = argc;
|
||||
*argv_p = argv;
|
||||
|
||||
if (buf)
|
||||
return 0;
|
||||
|
||||
iov.iov_base = &req->n;
|
||||
iov.iov_len = req->n.nlmsg_len;
|
||||
if (rtnl_talk_iov(&rth, &iov, 1, NULL) < 0) {
|
||||
if (rtnl_talk(&rth, &req.n, NULL) < 0) {
|
||||
fprintf(stderr, "We have an error talking to the kernel\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
*argc_p = argc;
|
||||
*argv_p = argv;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -712,7 +691,7 @@ bad_val:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_action(int argc, char **argv, void *buf, size_t buflen)
|
||||
int do_action(int argc, char **argv)
|
||||
{
|
||||
|
||||
int ret = 0;
|
||||
@ -722,12 +701,12 @@ int do_action(int argc, char **argv, void *buf, size_t buflen)
|
||||
if (matches(*argv, "add") == 0) {
|
||||
ret = tc_action_modify(RTM_NEWACTION,
|
||||
NLM_F_EXCL | NLM_F_CREATE,
|
||||
&argc, &argv, buf, buflen);
|
||||
&argc, &argv);
|
||||
} else if (matches(*argv, "change") == 0 ||
|
||||
matches(*argv, "replace") == 0) {
|
||||
ret = tc_action_modify(RTM_NEWACTION,
|
||||
NLM_F_CREATE | NLM_F_REPLACE,
|
||||
&argc, &argv, buf, buflen);
|
||||
&argc, &argv);
|
||||
} else if (matches(*argv, "delete") == 0) {
|
||||
argc -= 1;
|
||||
argv += 1;
|
||||
|
@ -167,7 +167,7 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg);
|
||||
|
||||
if (!tb[TCA_ACT_BPF_PARMS]) {
|
||||
fprintf(f, "[NULL bpf parameters]");
|
||||
fprintf(stderr, "Missing bpf parameters\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ static int print_connmark(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
|
||||
parse_rtattr_nested(tb, TCA_CONNMARK_MAX, arg);
|
||||
if (tb[TCA_CONNMARK_PARMS] == NULL) {
|
||||
print_string(PRINT_FP, NULL, "%s", "[NULL connmark parameters]");
|
||||
fprintf(stderr, "Missing connmark parameters\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ print_csum(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_CSUM_MAX, arg);
|
||||
|
||||
if (tb[TCA_CSUM_PARMS] == NULL) {
|
||||
fprintf(f, "[NULL csum parameters]");
|
||||
fprintf(stderr, "Missing csum parameters\n");
|
||||
return -1;
|
||||
}
|
||||
sel = RTA_DATA(tb[TCA_CSUM_PARMS]);
|
||||
|
@ -177,7 +177,7 @@ print_gact(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_GACT_MAX, arg);
|
||||
|
||||
if (tb[TCA_GACT_PARMS] == NULL) {
|
||||
print_string(PRINT_FP, NULL, "%s", "[NULL gact parameters]");
|
||||
fprintf(stderr, "Missing gact parameters\n");
|
||||
return -1;
|
||||
}
|
||||
p = RTA_DATA(tb[TCA_GACT_PARMS]);
|
||||
|
@ -218,7 +218,7 @@ skip_encode:
|
||||
|
||||
static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
{
|
||||
struct tc_ife *p = NULL;
|
||||
struct tc_ife *p;
|
||||
struct rtattr *tb[TCA_IFE_MAX + 1];
|
||||
__u16 ife_type = 0;
|
||||
__u32 mmark = 0;
|
||||
@ -233,7 +233,7 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_IFE_MAX, arg);
|
||||
|
||||
if (tb[TCA_IFE_PARMS] == NULL) {
|
||||
print_string(PRINT_FP, NULL, "%s", "[NULL ife parameters]");
|
||||
fprintf(stderr, "Missing ife parameters\n");
|
||||
return -1;
|
||||
}
|
||||
p = RTA_DATA(tb[TCA_IFE_PARMS]);
|
||||
|
94
tc/m_ipt.c
94
tc/m_ipt.c
@ -429,6 +429,8 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg)
|
||||
{
|
||||
struct rtattr *tb[TCA_IPT_MAX + 1];
|
||||
struct ipt_entry_target *t = NULL;
|
||||
struct xtables_target *m;
|
||||
__u32 hook;
|
||||
|
||||
if (arg == NULL)
|
||||
return -1;
|
||||
@ -440,70 +442,68 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_IPT_MAX, arg);
|
||||
|
||||
if (tb[TCA_IPT_TABLE] == NULL) {
|
||||
fprintf(f, "[NULL ipt table name ] assuming mangle ");
|
||||
fprintf(stderr, "Missing ipt table name, assuming mangle\n");
|
||||
} else {
|
||||
fprintf(f, "tablename: %s ",
|
||||
rta_getattr_str(tb[TCA_IPT_TABLE]));
|
||||
}
|
||||
|
||||
if (tb[TCA_IPT_HOOK] == NULL) {
|
||||
fprintf(f, "[NULL ipt hook name ]\n ");
|
||||
fprintf(stderr, "Missing ipt hook name\n ");
|
||||
return -1;
|
||||
} else {
|
||||
__u32 hook;
|
||||
|
||||
hook = rta_getattr_u32(tb[TCA_IPT_HOOK]);
|
||||
fprintf(f, " hook: %s\n", ipthooks[hook]);
|
||||
}
|
||||
|
||||
hook = rta_getattr_u32(tb[TCA_IPT_HOOK]);
|
||||
fprintf(f, " hook: %s\n", ipthooks[hook]);
|
||||
|
||||
if (tb[TCA_IPT_TARG] == NULL) {
|
||||
fprintf(f, "\t[NULL ipt target parameters ]\n");
|
||||
fprintf(stderr, "Missing ipt target parameters\n");
|
||||
return -1;
|
||||
} else {
|
||||
struct xtables_target *m = NULL;
|
||||
}
|
||||
|
||||
t = RTA_DATA(tb[TCA_IPT_TARG]);
|
||||
m = get_target_name(t->u.user.name);
|
||||
if (m != NULL) {
|
||||
if (build_st(m, t) < 0) {
|
||||
fprintf(stderr, " %s error\n", m->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
opts =
|
||||
merge_options(opts, m->extra_opts,
|
||||
&m->option_offset);
|
||||
} else {
|
||||
fprintf(stderr, " failed to find target %s\n\n",
|
||||
t->u.user.name);
|
||||
t = RTA_DATA(tb[TCA_IPT_TARG]);
|
||||
m = get_target_name(t->u.user.name);
|
||||
if (m != NULL) {
|
||||
if (build_st(m, t) < 0) {
|
||||
fprintf(stderr, " %s error\n", m->name);
|
||||
return -1;
|
||||
}
|
||||
fprintf(f, "\ttarget ");
|
||||
m->print(NULL, m->t, 0);
|
||||
if (tb[TCA_IPT_INDEX] == NULL) {
|
||||
fprintf(f, " [NULL ipt target index ]\n");
|
||||
} else {
|
||||
__u32 index;
|
||||
|
||||
index = rta_getattr_u32(tb[TCA_IPT_INDEX]);
|
||||
fprintf(f, "\n\tindex %u", index);
|
||||
}
|
||||
|
||||
if (tb[TCA_IPT_CNT]) {
|
||||
struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);
|
||||
|
||||
fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt);
|
||||
}
|
||||
if (show_stats) {
|
||||
if (tb[TCA_IPT_TM]) {
|
||||
struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);
|
||||
|
||||
print_tm(f, tm);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
|
||||
opts =
|
||||
merge_options(opts, m->extra_opts,
|
||||
&m->option_offset);
|
||||
} else {
|
||||
fprintf(stderr, " failed to find target %s\n\n",
|
||||
t->u.user.name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(f, "\ttarget ");
|
||||
m->print(NULL, m->t, 0);
|
||||
if (tb[TCA_IPT_INDEX] == NULL) {
|
||||
fprintf(stderr, "Missing ipt target index\n");
|
||||
} else {
|
||||
__u32 index;
|
||||
|
||||
index = rta_getattr_u32(tb[TCA_IPT_INDEX]);
|
||||
fprintf(f, "\n\tindex %u", index);
|
||||
}
|
||||
|
||||
if (tb[TCA_IPT_CNT]) {
|
||||
struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);
|
||||
|
||||
fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt);
|
||||
}
|
||||
if (show_stats) {
|
||||
if (tb[TCA_IPT_TM]) {
|
||||
struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);
|
||||
|
||||
print_tm(f, tm);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
|
||||
free_opts(opts);
|
||||
|
||||
return 0;
|
||||
|
@ -287,7 +287,7 @@ print_mirred(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_MIRRED_MAX, arg);
|
||||
|
||||
if (tb[TCA_MIRRED_PARMS] == NULL) {
|
||||
print_string(PRINT_FP, NULL, "%s", "[NULL mirred parameters]");
|
||||
fprintf(stderr, "Missing mirred parameters\n");
|
||||
return -1;
|
||||
}
|
||||
p = RTA_DATA(tb[TCA_MIRRED_PARMS]);
|
||||
|
@ -152,7 +152,7 @@ print_nat(struct action_util *au, FILE * f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_NAT_MAX, arg);
|
||||
|
||||
if (tb[TCA_NAT_PARMS] == NULL) {
|
||||
print_string(PRINT_FP, NULL, "%s", "[NULL nat parameters]");
|
||||
fprintf(stderr, "Missing nat parameters\n");
|
||||
return -1;
|
||||
}
|
||||
sel = RTA_DATA(tb[TCA_NAT_PARMS]);
|
||||
|
@ -742,7 +742,7 @@ static int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg);
|
||||
|
||||
if (!tb[TCA_PEDIT_PARMS] && !tb[TCA_PEDIT_PARMS_EX]) {
|
||||
fprintf(f, "[NULL pedit parameters]");
|
||||
fprintf(stderr, "Missing pedit parameters\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ static int print_sample(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
|
||||
if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] ||
|
||||
!tb[TCA_SAMPLE_PSAMPLE_GROUP]) {
|
||||
print_string(PRINT_FP, NULL, "%s", "[NULL sample parameters]");
|
||||
fprintf(stderr, "Missing sample parameters\n");
|
||||
return -1;
|
||||
}
|
||||
p = RTA_DATA(tb[TCA_SAMPLE_PARMS]);
|
||||
|
@ -171,13 +171,13 @@ static int print_simple(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_DEF_MAX, arg);
|
||||
|
||||
if (tb[TCA_DEF_PARMS] == NULL) {
|
||||
fprintf(f, "[NULL simple parameters]");
|
||||
fprintf(stderr, "Missing simple parameters\n");
|
||||
return -1;
|
||||
}
|
||||
sel = RTA_DATA(tb[TCA_DEF_PARMS]);
|
||||
|
||||
if (tb[TCA_DEF_DATA] == NULL) {
|
||||
fprintf(f, "[missing simple string]");
|
||||
fprintf(stderr, "Missing simple string\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,7 @@ static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
SPRINT_BUF(b1);
|
||||
__u32 priority;
|
||||
__u16 ptype;
|
||||
struct tc_skbedit *p = NULL;
|
||||
struct tc_skbedit *p;
|
||||
|
||||
if (arg == NULL)
|
||||
return -1;
|
||||
@ -204,7 +204,7 @@ static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_SKBEDIT_MAX, arg);
|
||||
|
||||
if (tb[TCA_SKBEDIT_PARMS] == NULL) {
|
||||
print_string(PRINT_FP, NULL, "%s", "[NULL skbedit parameters]");
|
||||
fprintf(stderr, "Missing skbedit parameters\n");
|
||||
return -1;
|
||||
}
|
||||
p = RTA_DATA(tb[TCA_SKBEDIT_PARMS]);
|
||||
|
@ -161,7 +161,7 @@ static int parse_skbmod(struct action_util *a, int *argc_p, char ***argv_p,
|
||||
|
||||
static int print_skbmod(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
{
|
||||
struct tc_skbmod *p = NULL;
|
||||
struct tc_skbmod *p;
|
||||
struct rtattr *tb[TCA_SKBMOD_MAX + 1];
|
||||
__u16 skbmod_etype = 0;
|
||||
int has_optional = 0;
|
||||
@ -174,7 +174,7 @@ static int print_skbmod(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_SKBMOD_MAX, arg);
|
||||
|
||||
if (tb[TCA_SKBMOD_PARMS] == NULL) {
|
||||
fprintf(f, "[NULL skbmod parameters]");
|
||||
fprintf(stderr, "Missing skbmod parameters\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -493,8 +493,7 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_TUNNEL_KEY_MAX, arg);
|
||||
|
||||
if (!tb[TCA_TUNNEL_KEY_PARMS]) {
|
||||
print_string(PRINT_FP, NULL, "%s",
|
||||
"[NULL tunnel_key parameters]");
|
||||
fprintf(stderr, "Missing tunnel_key parameters\n");
|
||||
return -1;
|
||||
}
|
||||
parm = RTA_DATA(tb[TCA_TUNNEL_KEY_PARMS]);
|
||||
|
@ -188,7 +188,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_VLAN_MAX, arg);
|
||||
|
||||
if (!tb[TCA_VLAN_PARMS]) {
|
||||
print_string(PRINT_FP, NULL, "%s", "[NULL vlan parameters]");
|
||||
fprintf(stderr, "Missing vlanparameters\n");
|
||||
return -1;
|
||||
}
|
||||
parm = RTA_DATA(tb[TCA_VLAN_PARMS]);
|
||||
|
15
tc/m_xt.c
15
tc/m_xt.c
@ -317,6 +317,7 @@ print_ipt(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
struct xtables_target *m;
|
||||
struct rtattr *tb[TCA_IPT_MAX + 1];
|
||||
struct xt_entry_target *t = NULL;
|
||||
__u32 hook;
|
||||
|
||||
if (arg == NULL)
|
||||
return -1;
|
||||
@ -330,27 +331,25 @@ print_ipt(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_IPT_MAX, arg);
|
||||
|
||||
if (tb[TCA_IPT_TABLE] == NULL) {
|
||||
fprintf(f, "[NULL ipt table name ] assuming mangle ");
|
||||
fprintf(stderr, "Missing ipt table name, assuming mangle\n");
|
||||
} else {
|
||||
fprintf(f, "tablename: %s ",
|
||||
rta_getattr_str(tb[TCA_IPT_TABLE]));
|
||||
}
|
||||
|
||||
if (tb[TCA_IPT_HOOK] == NULL) {
|
||||
fprintf(f, "[NULL ipt hook name ]\n ");
|
||||
fprintf(stderr, "Missing ipt hook name\n ");
|
||||
return -1;
|
||||
} else {
|
||||
__u32 hook;
|
||||
|
||||
hook = rta_getattr_u32(tb[TCA_IPT_HOOK]);
|
||||
fprintf(f, " hook: %s\n", ipthooks[hook]);
|
||||
}
|
||||
|
||||
if (tb[TCA_IPT_TARG] == NULL) {
|
||||
fprintf(f, "\t[NULL ipt target parameters ]\n");
|
||||
fprintf(stderr, "Missing ipt target parameters\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hook = rta_getattr_u32(tb[TCA_IPT_HOOK]);
|
||||
fprintf(f, " hook: %s\n", ipthooks[hook]);
|
||||
|
||||
t = RTA_DATA(tb[TCA_IPT_TARG]);
|
||||
m = xtables_find_target(t->u.user.name, XTF_TRY_LOAD);
|
||||
if (!m) {
|
||||
|
@ -354,6 +354,8 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg)
|
||||
{
|
||||
struct rtattr *tb[TCA_IPT_MAX + 1];
|
||||
struct xt_entry_target *t = NULL;
|
||||
struct xtables_target *m;
|
||||
__u32 hook;
|
||||
|
||||
if (arg == NULL)
|
||||
return -1;
|
||||
@ -363,70 +365,66 @@ print_ipt(struct action_util *au, FILE * f, struct rtattr *arg)
|
||||
parse_rtattr_nested(tb, TCA_IPT_MAX, arg);
|
||||
|
||||
if (tb[TCA_IPT_TABLE] == NULL) {
|
||||
fprintf(f, "[NULL ipt table name ] assuming mangle ");
|
||||
fprintf(stderr, "Missing ipt table name, assuming mangle\n");
|
||||
} else {
|
||||
fprintf(f, "tablename: %s ",
|
||||
rta_getattr_str(tb[TCA_IPT_TABLE]));
|
||||
}
|
||||
|
||||
if (tb[TCA_IPT_HOOK] == NULL) {
|
||||
fprintf(f, "[NULL ipt hook name ]\n ");
|
||||
fprintf(stderr, "Missing ipt hook name\n");
|
||||
return -1;
|
||||
} else {
|
||||
__u32 hook;
|
||||
|
||||
hook = rta_getattr_u32(tb[TCA_IPT_HOOK]);
|
||||
fprintf(f, " hook: %s\n", ipthooks[hook]);
|
||||
}
|
||||
|
||||
if (tb[TCA_IPT_TARG] == NULL) {
|
||||
fprintf(f, "\t[NULL ipt target parameters ]\n");
|
||||
fprintf(stderr, "Missing ipt target parameters\n");
|
||||
return -1;
|
||||
} else {
|
||||
struct xtables_target *m = NULL;
|
||||
}
|
||||
|
||||
t = RTA_DATA(tb[TCA_IPT_TARG]);
|
||||
m = find_target(t->u.user.name, TRY_LOAD);
|
||||
if (m != NULL) {
|
||||
if (build_st(m, t) < 0) {
|
||||
fprintf(stderr, " %s error\n", m->name);
|
||||
return -1;
|
||||
}
|
||||
hook = rta_getattr_u32(tb[TCA_IPT_HOOK]);
|
||||
fprintf(f, " hook: %s\n", ipthooks[hook]);
|
||||
|
||||
opts =
|
||||
merge_options(opts, m->extra_opts,
|
||||
&m->option_offset);
|
||||
} else {
|
||||
fprintf(stderr, " failed to find target %s\n\n",
|
||||
t->u.user.name);
|
||||
t = RTA_DATA(tb[TCA_IPT_TARG]);
|
||||
m = find_target(t->u.user.name, TRY_LOAD);
|
||||
if (m != NULL) {
|
||||
if (build_st(m, t) < 0) {
|
||||
fprintf(stderr, " %s error\n", m->name);
|
||||
return -1;
|
||||
}
|
||||
fprintf(f, "\ttarget ");
|
||||
m->print(NULL, m->t, 0);
|
||||
if (tb[TCA_IPT_INDEX] == NULL) {
|
||||
fprintf(f, " [NULL ipt target index ]\n");
|
||||
} else {
|
||||
__u32 index;
|
||||
|
||||
index = rta_getattr_u32(tb[TCA_IPT_INDEX]);
|
||||
fprintf(f, "\n\tindex %u", index);
|
||||
}
|
||||
|
||||
if (tb[TCA_IPT_CNT]) {
|
||||
struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);
|
||||
|
||||
fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt);
|
||||
}
|
||||
if (show_stats) {
|
||||
if (tb[TCA_IPT_TM]) {
|
||||
struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);
|
||||
|
||||
print_tm(f, tm);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
|
||||
opts =
|
||||
merge_options(opts, m->extra_opts,
|
||||
&m->option_offset);
|
||||
} else {
|
||||
fprintf(stderr, " failed to find target %s\n\n",
|
||||
t->u.user.name);
|
||||
return -1;
|
||||
}
|
||||
fprintf(f, "\ttarget ");
|
||||
m->print(NULL, m->t, 0);
|
||||
if (tb[TCA_IPT_INDEX] == NULL) {
|
||||
fprintf(f, " [NULL ipt target index ]\n");
|
||||
} else {
|
||||
__u32 index;
|
||||
|
||||
index = rta_getattr_u32(tb[TCA_IPT_INDEX]);
|
||||
fprintf(f, "\n\tindex %u", index);
|
||||
}
|
||||
|
||||
if (tb[TCA_IPT_CNT]) {
|
||||
struct tc_cnt *c = RTA_DATA(tb[TCA_IPT_CNT]);
|
||||
|
||||
fprintf(f, " ref %d bind %d", c->refcnt, c->bindcnt);
|
||||
}
|
||||
if (show_stats) {
|
||||
if (tb[TCA_IPT_TM]) {
|
||||
struct tcf_t *tm = RTA_DATA(tb[TCA_IPT_TM]);
|
||||
|
||||
print_tm(f, tm);
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
|
||||
free_opts(opts);
|
||||
|
||||
return 0;
|
||||
|
202
tc/tc.c
202
tc/tc.c
@ -205,18 +205,18 @@ static void usage(void)
|
||||
" -nm | -nam[es] | { -cf | -conf } path }\n");
|
||||
}
|
||||
|
||||
static int do_cmd(int argc, char **argv, void *buf, size_t buflen)
|
||||
static int do_cmd(int argc, char **argv)
|
||||
{
|
||||
if (matches(*argv, "qdisc") == 0)
|
||||
return do_qdisc(argc-1, argv+1);
|
||||
if (matches(*argv, "class") == 0)
|
||||
return do_class(argc-1, argv+1);
|
||||
if (matches(*argv, "filter") == 0)
|
||||
return do_filter(argc-1, argv+1, buf, buflen);
|
||||
return do_filter(argc-1, argv+1);
|
||||
if (matches(*argv, "chain") == 0)
|
||||
return do_chain(argc-1, argv+1, buf, buflen);
|
||||
return do_chain(argc-1, argv+1);
|
||||
if (matches(*argv, "actions") == 0)
|
||||
return do_action(argc-1, argv+1, buf, buflen);
|
||||
return do_action(argc-1, argv+1);
|
||||
if (matches(*argv, "monitor") == 0)
|
||||
return do_tcmonitor(argc-1, argv+1);
|
||||
if (matches(*argv, "exec") == 0)
|
||||
@ -231,111 +231,11 @@ static int do_cmd(int argc, char **argv, void *buf, size_t buflen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define TC_MAX_SUBC 10
|
||||
static bool batchsize_enabled(int argc, char *argv[])
|
||||
{
|
||||
struct {
|
||||
char *c;
|
||||
char *subc[TC_MAX_SUBC];
|
||||
} table[] = {
|
||||
{ "filter", { "add", "delete", "change", "replace", NULL} },
|
||||
{ "actions", { "add", "change", "replace", NULL} },
|
||||
{ NULL },
|
||||
}, *iter;
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
if (argc < 2)
|
||||
return false;
|
||||
|
||||
for (iter = table; iter->c; iter++) {
|
||||
if (matches(argv[0], iter->c))
|
||||
continue;
|
||||
for (i = 0; i < TC_MAX_SUBC; i++) {
|
||||
s = iter->subc[i];
|
||||
if (s && matches(argv[1], s) == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct batch_buf {
|
||||
struct batch_buf *next;
|
||||
char buf[16420]; /* sizeof (struct nlmsghdr) +
|
||||
max(sizeof (struct tcmsg) +
|
||||
sizeof (struct tcamsg)) +
|
||||
MAX_MSG */
|
||||
};
|
||||
|
||||
static struct batch_buf *get_batch_buf(struct batch_buf **pool,
|
||||
struct batch_buf **head,
|
||||
struct batch_buf **tail)
|
||||
{
|
||||
struct batch_buf *buf;
|
||||
|
||||
if (*pool == NULL)
|
||||
buf = calloc(1, sizeof(struct batch_buf));
|
||||
else {
|
||||
buf = *pool;
|
||||
*pool = (*pool)->next;
|
||||
memset(buf, 0, sizeof(struct batch_buf));
|
||||
}
|
||||
|
||||
if (*head == NULL)
|
||||
*head = *tail = buf;
|
||||
else {
|
||||
(*tail)->next = buf;
|
||||
(*tail) = buf;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void put_batch_bufs(struct batch_buf **pool,
|
||||
struct batch_buf **head,
|
||||
struct batch_buf **tail)
|
||||
{
|
||||
if (*head == NULL || *tail == NULL)
|
||||
return;
|
||||
|
||||
if (*pool == NULL)
|
||||
*pool = *head;
|
||||
else {
|
||||
(*tail)->next = *pool;
|
||||
*pool = *head;
|
||||
}
|
||||
*head = NULL;
|
||||
*tail = NULL;
|
||||
}
|
||||
|
||||
static void free_batch_bufs(struct batch_buf **pool)
|
||||
{
|
||||
struct batch_buf *buf;
|
||||
|
||||
for (buf = *pool; buf != NULL; buf = *pool) {
|
||||
*pool = buf->next;
|
||||
free(buf);
|
||||
}
|
||||
*pool = NULL;
|
||||
}
|
||||
|
||||
static int batch(const char *name)
|
||||
{
|
||||
struct batch_buf *head = NULL, *tail = NULL, *buf_pool = NULL;
|
||||
char *largv[100], *largv_next[100];
|
||||
char *line, *line_next = NULL;
|
||||
bool bs_enabled = false;
|
||||
bool lastline = false;
|
||||
int largc, largc_next;
|
||||
bool bs_enabled_saved;
|
||||
bool bs_enabled_next;
|
||||
int batchsize = 0;
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
int ret = 0;
|
||||
int err;
|
||||
bool send;
|
||||
|
||||
batch_mode = 1;
|
||||
if (name && strcmp(name, "-") != 0) {
|
||||
@ -355,96 +255,26 @@ static int batch(const char *name)
|
||||
}
|
||||
|
||||
cmdlineno = 0;
|
||||
if (getcmdline(&line, &len, stdin) == -1)
|
||||
goto Exit;
|
||||
largc = makeargs(line, largv, 100);
|
||||
bs_enabled = batchsize_enabled(largc, largv);
|
||||
do {
|
||||
if (getcmdline(&line_next, &len, stdin) == -1)
|
||||
lastline = true;
|
||||
while (getcmdline(&line, &len, stdin) != -1) {
|
||||
char *largv[100];
|
||||
int largc;
|
||||
|
||||
largc_next = makeargs(line_next, largv_next, 100);
|
||||
bs_enabled_next = batchsize_enabled(largc_next, largv_next);
|
||||
if (bs_enabled) {
|
||||
struct batch_buf *buf;
|
||||
|
||||
buf = get_batch_buf(&buf_pool, &head, &tail);
|
||||
if (!buf) {
|
||||
fprintf(stderr,
|
||||
"failed to allocate batch_buf\n");
|
||||
return -1;
|
||||
}
|
||||
++batchsize;
|
||||
}
|
||||
|
||||
/*
|
||||
* In batch mode, if we haven't accumulated enough commands
|
||||
* and this is not the last command and this command & next
|
||||
* command both support the batchsize feature, don't send the
|
||||
* message immediately.
|
||||
*/
|
||||
if (!lastline && bs_enabled && bs_enabled_next
|
||||
&& batchsize != MSG_IOV_MAX)
|
||||
send = false;
|
||||
else
|
||||
send = true;
|
||||
|
||||
line = line_next;
|
||||
line_next = NULL;
|
||||
len = 0;
|
||||
bs_enabled_saved = bs_enabled;
|
||||
bs_enabled = bs_enabled_next;
|
||||
|
||||
if (largc == 0) {
|
||||
largc = largc_next;
|
||||
memcpy(largv, largv_next, largc * sizeof(char *));
|
||||
largc = makeargs(line, largv, 100);
|
||||
if (largc == 0)
|
||||
continue; /* blank line */
|
||||
}
|
||||
|
||||
err = do_cmd(largc, largv, tail == NULL ? NULL : tail->buf,
|
||||
tail == NULL ? 0 : sizeof(tail->buf));
|
||||
fflush(stdout);
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "Command failed %s:%d\n", name,
|
||||
cmdlineno - 1);
|
||||
if (do_cmd(largc, largv)) {
|
||||
fprintf(stderr, "Command failed %s:%d\n",
|
||||
name, cmdlineno);
|
||||
ret = 1;
|
||||
if (!force)
|
||||
break;
|
||||
}
|
||||
largc = largc_next;
|
||||
memcpy(largv, largv_next, largc * sizeof(char *));
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if (send && bs_enabled_saved) {
|
||||
struct iovec *iov, *iovs;
|
||||
struct batch_buf *buf;
|
||||
struct nlmsghdr *n;
|
||||
|
||||
iov = iovs = malloc(batchsize * sizeof(struct iovec));
|
||||
for (buf = head; buf != NULL; buf = buf->next, ++iov) {
|
||||
n = (struct nlmsghdr *)&buf->buf;
|
||||
iov->iov_base = n;
|
||||
iov->iov_len = n->nlmsg_len;
|
||||
}
|
||||
|
||||
err = rtnl_talk_iov(&rth, iovs, batchsize, NULL);
|
||||
put_batch_bufs(&buf_pool, &head, &tail);
|
||||
free(iovs);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "Command failed %s:%d\n", name,
|
||||
cmdlineno - (batchsize + err) - 1);
|
||||
ret = 1;
|
||||
if (!force)
|
||||
break;
|
||||
}
|
||||
batchsize = 0;
|
||||
}
|
||||
} while (!lastline);
|
||||
|
||||
free_batch_bufs(&buf_pool);
|
||||
Exit:
|
||||
free(line);
|
||||
rtnl_close(&rth);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -538,7 +368,7 @@ int main(int argc, char **argv)
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
ret = do_cmd(argc-1, argv+1, NULL, 0);
|
||||
ret = do_cmd(argc-1, argv+1);
|
||||
Exit:
|
||||
rtnl_close(&rth);
|
||||
|
||||
|
@ -1,15 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#define TCA_BUF_MAX (64*1024)
|
||||
#define MSG_IOV_MAX 128
|
||||
|
||||
extern struct rtnl_handle rth;
|
||||
|
||||
int do_qdisc(int argc, char **argv);
|
||||
int do_class(int argc, char **argv);
|
||||
int do_filter(int argc, char **argv, void *buf, size_t buflen);
|
||||
int do_chain(int argc, char **argv, void *buf, size_t buflen);
|
||||
int do_action(int argc, char **argv, void *buf, size_t buflen);
|
||||
int do_filter(int argc, char **argv);
|
||||
int do_chain(int argc, char **argv);
|
||||
int do_action(int argc, char **argv);
|
||||
int do_tcmonitor(int argc, char **argv);
|
||||
int do_exec(int argc, char **argv);
|
||||
|
||||
|
134
tc/tc_filter.c
134
tc/tc_filter.c
@ -58,42 +58,30 @@ struct tc_filter_req {
|
||||
char buf[MAX_MSG];
|
||||
};
|
||||
|
||||
static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv,
|
||||
void *buf, size_t buflen)
|
||||
static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
|
||||
{
|
||||
struct tc_filter_req *req, filter_req;
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct tcmsg t;
|
||||
char buf[MAX_MSG];
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST | flags,
|
||||
.n.nlmsg_type = cmd,
|
||||
.t.tcm_family = AF_UNSPEC,
|
||||
};
|
||||
struct filter_util *q = NULL;
|
||||
struct tc_estimator est = {};
|
||||
char k[FILTER_NAMESZ] = {};
|
||||
int chain_index_set = 0;
|
||||
char d[IFNAMSIZ] = {};
|
||||
int protocol_set = 0;
|
||||
__u32 block_index = 0;
|
||||
char *fhandle = NULL;
|
||||
__u32 protocol = 0;
|
||||
__u32 chain_index;
|
||||
struct iovec iov;
|
||||
__u32 prio = 0;
|
||||
int ret;
|
||||
__u32 protocol = 0;
|
||||
int protocol_set = 0;
|
||||
__u32 chain_index;
|
||||
int chain_index_set = 0;
|
||||
char *fhandle = NULL;
|
||||
char d[IFNAMSIZ] = {};
|
||||
char k[FILTER_NAMESZ] = {};
|
||||
struct tc_estimator est = {};
|
||||
|
||||
if (buf) {
|
||||
req = buf;
|
||||
if (buflen < sizeof (struct tc_filter_req)) {
|
||||
fprintf(stderr, "buffer is too small: %zu\n", buflen);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
memset(&filter_req, 0, sizeof (struct tc_filter_req));
|
||||
req = &filter_req;
|
||||
}
|
||||
|
||||
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
|
||||
req->n.nlmsg_flags = NLM_F_REQUEST | flags;
|
||||
req->n.nlmsg_type = cmd;
|
||||
req->t.tcm_family = AF_UNSPEC;
|
||||
|
||||
if ((cmd == RTM_NEWTFILTER || cmd == RTM_NEWCHAIN) &&
|
||||
flags & NLM_F_CREATE)
|
||||
if (cmd == RTM_NEWTFILTER && flags & NLM_F_CREATE)
|
||||
protocol = htons(ETH_P_ALL);
|
||||
|
||||
while (argc > 0) {
|
||||
@ -101,53 +89,39 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv,
|
||||
NEXT_ARG();
|
||||
if (d[0])
|
||||
duparg("dev", *argv);
|
||||
if (block_index) {
|
||||
fprintf(stderr, "Error: \"dev\" and \"block\" are mutually exlusive\n");
|
||||
return -1;
|
||||
}
|
||||
strncpy(d, *argv, sizeof(d)-1);
|
||||
} else if (matches(*argv, "block") == 0) {
|
||||
NEXT_ARG();
|
||||
if (block_index)
|
||||
duparg("block", *argv);
|
||||
if (d[0]) {
|
||||
fprintf(stderr, "Error: \"dev\" and \"block\" are mutually exlusive\n");
|
||||
return -1;
|
||||
}
|
||||
if (get_u32(&block_index, *argv, 0) || !block_index)
|
||||
invarg("invalid block index value", *argv);
|
||||
} else if (strcmp(*argv, "root") == 0) {
|
||||
if (req->t.tcm_parent) {
|
||||
if (req.t.tcm_parent) {
|
||||
fprintf(stderr,
|
||||
"Error: \"root\" is duplicate parent ID\n");
|
||||
return -1;
|
||||
}
|
||||
req->t.tcm_parent = TC_H_ROOT;
|
||||
req.t.tcm_parent = TC_H_ROOT;
|
||||
} else if (strcmp(*argv, "ingress") == 0) {
|
||||
if (req->t.tcm_parent) {
|
||||
if (req.t.tcm_parent) {
|
||||
fprintf(stderr,
|
||||
"Error: \"ingress\" is duplicate parent ID\n");
|
||||
return -1;
|
||||
}
|
||||
req->t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
|
||||
req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
|
||||
TC_H_MIN_INGRESS);
|
||||
} else if (strcmp(*argv, "egress") == 0) {
|
||||
if (req->t.tcm_parent) {
|
||||
if (req.t.tcm_parent) {
|
||||
fprintf(stderr,
|
||||
"Error: \"egress\" is duplicate parent ID\n");
|
||||
return -1;
|
||||
}
|
||||
req->t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
|
||||
req.t.tcm_parent = TC_H_MAKE(TC_H_CLSACT,
|
||||
TC_H_MIN_EGRESS);
|
||||
} else if (strcmp(*argv, "parent") == 0) {
|
||||
__u32 handle;
|
||||
|
||||
NEXT_ARG();
|
||||
if (req->t.tcm_parent)
|
||||
if (req.t.tcm_parent)
|
||||
duparg("parent", *argv);
|
||||
if (get_tc_classid(&handle, *argv))
|
||||
invarg("Invalid parent ID", *argv);
|
||||
req->t.tcm_parent = handle;
|
||||
req.t.tcm_parent = handle;
|
||||
} else if (strcmp(*argv, "handle") == 0) {
|
||||
NEXT_ARG();
|
||||
if (fhandle)
|
||||
@ -194,27 +168,26 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv,
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
req->t.tcm_info = TC_H_MAKE(prio<<16, protocol);
|
||||
req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
|
||||
|
||||
if (chain_index_set)
|
||||
addattr32(&req->n, sizeof(*req), TCA_CHAIN, chain_index);
|
||||
addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
|
||||
|
||||
if (k[0])
|
||||
addattr_l(&req->n, sizeof(*req), TCA_KIND, k, strlen(k)+1);
|
||||
addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
|
||||
|
||||
if (d[0]) {
|
||||
ll_init_map(&rth);
|
||||
|
||||
req->t.tcm_ifindex = ll_name_to_index(d);
|
||||
if (!req->t.tcm_ifindex)
|
||||
return -nodev(d);
|
||||
} else if (block_index) {
|
||||
req->t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
|
||||
req->t.tcm_block_index = block_index;
|
||||
req.t.tcm_ifindex = ll_name_to_index(d);
|
||||
if (req.t.tcm_ifindex == 0) {
|
||||
fprintf(stderr, "Cannot find device \"%s\"\n", d);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (q) {
|
||||
if (q->parse_fopt(q, fhandle, argc, argv, &req->n))
|
||||
if (q->parse_fopt(q, fhandle, argc, argv, &req.n))
|
||||
return 1;
|
||||
} else {
|
||||
if (fhandle) {
|
||||
@ -233,16 +206,10 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv,
|
||||
}
|
||||
|
||||
if (est.ewma_log)
|
||||
addattr_l(&req->n, sizeof(*req), TCA_RATE, &est, sizeof(est));
|
||||
addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));
|
||||
|
||||
if (buf)
|
||||
return 0;
|
||||
|
||||
iov.iov_base = &req->n;
|
||||
iov.iov_len = req->n.nlmsg_len;
|
||||
ret = rtnl_talk_iov(&rth, &iov, 1, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "We have an error talking to the kernel, %d\n", ret);
|
||||
if (rtnl_talk(&rth, &req.n, NULL) < 0) {
|
||||
fprintf(stderr, "We have an error talking to the kernel\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
@ -375,8 +342,7 @@ int print_filter(struct nlmsghdr *n, void *arg)
|
||||
if (q)
|
||||
q->print_fopt(q, fp, tb[TCA_OPTIONS], t->tcm_handle);
|
||||
else
|
||||
print_string(PRINT_FP, NULL,
|
||||
"[cannot parse parameters]", NULL);
|
||||
fprintf(stderr, "cannot parse option parameters\n");
|
||||
close_json_object();
|
||||
}
|
||||
}
|
||||
@ -752,22 +718,20 @@ static int tc_filter_list(int cmd, int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_filter(int argc, char **argv, void *buf, size_t buflen)
|
||||
int do_filter(int argc, char **argv)
|
||||
{
|
||||
if (argc < 1)
|
||||
return tc_filter_list(RTM_GETTFILTER, 0, NULL);
|
||||
if (matches(*argv, "add") == 0)
|
||||
return tc_filter_modify(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE,
|
||||
argc-1, argv+1, buf, buflen);
|
||||
argc-1, argv+1);
|
||||
if (matches(*argv, "change") == 0)
|
||||
return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1,
|
||||
buf, buflen);
|
||||
return tc_filter_modify(RTM_NEWTFILTER, 0, argc-1, argv+1);
|
||||
if (matches(*argv, "replace") == 0)
|
||||
return tc_filter_modify(RTM_NEWTFILTER, NLM_F_CREATE, argc-1,
|
||||
argv+1, buf, buflen);
|
||||
argv+1);
|
||||
if (matches(*argv, "delete") == 0)
|
||||
return tc_filter_modify(RTM_DELTFILTER, 0, argc-1, argv+1,
|
||||
buf, buflen);
|
||||
return tc_filter_modify(RTM_DELTFILTER, 0, argc-1, argv+1);
|
||||
if (matches(*argv, "get") == 0)
|
||||
return tc_filter_get(RTM_GETTFILTER, 0, argc-1, argv+1);
|
||||
if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
|
||||
@ -782,16 +746,16 @@ int do_filter(int argc, char **argv, void *buf, size_t buflen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int do_chain(int argc, char **argv, void *buf, size_t buflen)
|
||||
int do_chain(int argc, char **argv)
|
||||
{
|
||||
if (argc < 1)
|
||||
return tc_filter_list(RTM_GETCHAIN, 0, NULL);
|
||||
if (matches(*argv, "add") == 0) {
|
||||
return tc_filter_modify(RTM_NEWCHAIN, NLM_F_EXCL | NLM_F_CREATE,
|
||||
argc - 1, argv + 1, buf, buflen);
|
||||
argc - 1, argv + 1);
|
||||
} else if (matches(*argv, "delete") == 0) {
|
||||
return tc_filter_modify(RTM_DELCHAIN, 0,
|
||||
argc - 1, argv + 1, buf, buflen);
|
||||
argc - 1, argv + 1);
|
||||
} else if (matches(*argv, "get") == 0) {
|
||||
return tc_filter_get(RTM_GETCHAIN, 0,
|
||||
argc - 1, argv + 1);
|
||||
|
@ -313,8 +313,7 @@ int print_qdisc(struct nlmsghdr *n, void *arg)
|
||||
if (q)
|
||||
q->print_qopt(q, fp, tb[TCA_OPTIONS]);
|
||||
else
|
||||
print_string(PRINT_FP, NULL,
|
||||
"[cannot parse qdisc parameters]", NULL);
|
||||
fprintf(stderr, "Cannot parse qdisc parameters\n");
|
||||
}
|
||||
close_json_object();
|
||||
|
||||
|
17
tc/tc_util.c
17
tc/tc_util.c
@ -198,7 +198,7 @@ int parse_percent(double *val, const char *str)
|
||||
char *p;
|
||||
|
||||
*val = strtod(str, &p) / 100.;
|
||||
if (*val == HUGE_VALF || *val == HUGE_VALL)
|
||||
if (*val > 1.0 || *val < 0.0)
|
||||
return 1;
|
||||
if (*p && strcmp(p, "%"))
|
||||
return -1;
|
||||
@ -226,16 +226,16 @@ static int parse_percent_rate(char *rate, size_t len,
|
||||
if (ret != 1)
|
||||
goto malf;
|
||||
|
||||
if (parse_percent(&perc, str_perc))
|
||||
ret = parse_percent(&perc, str_perc);
|
||||
if (ret == 1) {
|
||||
fprintf(stderr, "Invalid rate specified; should be between [0,100]%% but is %s\n", str);
|
||||
goto err;
|
||||
} else if (ret == -1) {
|
||||
goto malf;
|
||||
}
|
||||
|
||||
free(str_perc);
|
||||
|
||||
if (perc > 1.0 || perc < 0.0) {
|
||||
fprintf(stderr, "Invalid rate specified; should be between [0,100]%% but is %s\n", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rate_bit = perc * dev_mbit * 1000 * 1000;
|
||||
|
||||
ret = snprintf(rate, len, "%lf", rate_bit);
|
||||
@ -247,8 +247,9 @@ static int parse_percent_rate(char *rate, size_t len,
|
||||
return 0;
|
||||
|
||||
malf:
|
||||
free(str_perc);
|
||||
fprintf(stderr, "Specified rate value could not be read or is malformed\n");
|
||||
err:
|
||||
free(str_perc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user