Merge branch 'master' of ../iproute2-next

This commit is contained in:
Stephen Hemminger 2019-03-19 10:32:45 -07:00
commit 50cf634899
75 changed files with 3554 additions and 1255 deletions

130
.clang-format Normal file
View File

@ -0,0 +1,130 @@
# SPDX-License-Identifier: GPL-2.0
#
# clang-format configuration file. Intended for clang-format >= 4.
#
# For more information, see:
#
# Documentation/process/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
#AfterExternBlock: false # Unknown to clang-format-5.0
BeforeCatch: false
BeforeElse: false
IndentBraces: false
#SplitEmptyFunction: true # Unknown to clang-format-4.0
#SplitEmptyRecord: true # Unknown to clang-format-4.0
#SplitEmptyNamespace: true # Unknown to clang-format-4.0
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
#CompactNamespaces: false # Unknown to clang-format-4.0
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
#FixNamespaceComments: false # Unknown to clang-format-4.0
# Taken from:
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
# | sort | uniq
ForEachMacros:
- 'list_for_each_entry'
- 'list_for_each_entry_safe'
- 'mnl_attr_for_each_nested'
- 'hlist_for_each'
- 'hlist_for_each_safe'
- 'hlist_for_each_entry'
#IncludeBlocks: Preserve # Unknown to clang-format-5.0
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
#IndentPPDirectives: None # Unknown to clang-format-5.0
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: Inner
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
# Taken from git's rules
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
#SortUsingDeclarations: false # Unknown to clang-format-4.0
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
SpaceBeforeParens: ControlStatements
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
...

View File

@ -39,6 +39,7 @@ static void usage(void)
" [ self ] [ master ] [ use ] [ router ] [ extern_learn ]\n" " [ self ] [ master ] [ use ] [ router ] [ extern_learn ]\n"
" [ sticky ] [ local | static | dynamic ] [ dst IPADDR ]\n" " [ sticky ] [ local | static | dynamic ] [ dst IPADDR ]\n"
" [ vlan VID ] [ port PORT] [ vni VNI ] [ via DEV ]\n" " [ vlan VID ] [ port PORT] [ vni VNI ] [ via DEV ]\n"
" [ src_vni VNI ]\n"
" bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] [ state STATE ] ]\n"); " bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] [ state STATE ] ]\n");
exit(-1); exit(-1);
} }
@ -383,6 +384,7 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
inet_prefix dst; inet_prefix dst;
unsigned long port = 0; unsigned long port = 0;
unsigned long vni = ~0; unsigned long vni = ~0;
unsigned long src_vni = ~0;
unsigned int via = 0; unsigned int via = 0;
char *endptr; char *endptr;
short vid = -1; short vid = -1;
@ -416,6 +418,12 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
if ((endptr && *endptr) || if ((endptr && *endptr) ||
(vni >> 24) || vni == ULONG_MAX) (vni >> 24) || vni == ULONG_MAX)
invarg("invalid VNI\n", *argv); invarg("invalid VNI\n", *argv);
} else if (strcmp(*argv, "src_vni") == 0) {
NEXT_ARG();
src_vni = strtoul(*argv, &endptr, 0);
if ((endptr && *endptr) ||
(src_vni >> 24) || src_vni == ULONG_MAX)
invarg("invalid src VNI\n", *argv);
} else if (strcmp(*argv, "via") == 0) { } else if (strcmp(*argv, "via") == 0) {
NEXT_ARG(); NEXT_ARG();
via = ll_name_to_index(*argv); via = ll_name_to_index(*argv);
@ -495,6 +503,8 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
} }
if (vni != ~0) if (vni != ~0)
addattr32(&req.n, sizeof(req), NDA_VNI, vni); addattr32(&req.n, sizeof(req), NDA_VNI, vni);
if (src_vni != ~0)
addattr32(&req.n, sizeof(req), NDA_SRC_VNI, src_vni);
if (via) if (via)
addattr32(&req.n, sizeof(req), NDA_IFINDEX, via); addattr32(&req.n, sizeof(req), NDA_IFINDEX, via);

File diff suppressed because it is too large Load Diff

View File

@ -272,7 +272,7 @@ const char *bpf_prog_to_default_section(enum bpf_prog_type type);
int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv); int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv);
int bpf_trace_pipe(void); int bpf_trace_pipe(void);
void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len); void bpf_print_ops(struct rtattr *bpf_ops, __u16 len);
int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns,
size_t size_insns, const char *license, char *log, size_t size_insns, const char *license, char *log,

View File

@ -9,6 +9,7 @@ unsigned ll_name_to_index(const char *name);
const char *ll_index_to_name(unsigned idx); const char *ll_index_to_name(unsigned idx);
int ll_index_to_type(unsigned idx); int ll_index_to_type(unsigned idx);
int ll_index_to_flags(unsigned idx); int ll_index_to_flags(unsigned idx);
void ll_drop_by_index(unsigned index);
unsigned namehash(const char *str); unsigned namehash(const char *str);
const char *ll_idx_n2a(unsigned int idx); const char *ll_idx_n2a(unsigned int idx);

View File

@ -14,6 +14,7 @@
/* Extended instruction set based on top of classic BPF */ /* Extended instruction set based on top of classic BPF */
/* instruction classes */ /* instruction classes */
#define BPF_JMP32 0x06 /* jmp mode in word width */
#define BPF_ALU64 0x07 /* alu mode in double word width */ #define BPF_ALU64 0x07 /* alu mode in double word width */
/* ld/ldx fields */ /* ld/ldx fields */
@ -266,6 +267,7 @@ enum bpf_attach_type {
#define BPF_ANY 0 /* create new element or update existing */ #define BPF_ANY 0 /* create new element or update existing */
#define BPF_NOEXIST 1 /* create new element if it didn't exist */ #define BPF_NOEXIST 1 /* create new element if it didn't exist */
#define BPF_EXIST 2 /* update existing element */ #define BPF_EXIST 2 /* update existing element */
#define BPF_F_LOCK 4 /* spin_lock-ed map_lookup/map_update */
/* flags for BPF_MAP_CREATE command */ /* flags for BPF_MAP_CREATE command */
#define BPF_F_NO_PREALLOC (1U << 0) #define BPF_F_NO_PREALLOC (1U << 0)
@ -2014,6 +2016,19 @@ union bpf_attr {
* Only works if *skb* contains an IPv6 packet. Insert a * Only works if *skb* contains an IPv6 packet. Insert a
* Segment Routing Header (**struct ipv6_sr_hdr**) inside * Segment Routing Header (**struct ipv6_sr_hdr**) inside
* the IPv6 header. * the IPv6 header.
* **BPF_LWT_ENCAP_IP**
* IP encapsulation (GRE/GUE/IPIP/etc). The outer header
* must be IPv4 or IPv6, followed by zero or more
* additional headers, up to LWT_BPF_MAX_HEADROOM total
* bytes in all prepended headers. Please note that
* if skb_is_gso(skb) is true, no more than two headers
* can be prepended, and the inner header, if present,
* should be either GRE or UDP/GUE.
*
* BPF_LWT_ENCAP_SEG6*** types can be called by bpf programs of
* type BPF_PROG_TYPE_LWT_IN; BPF_LWT_ENCAP_IP type can be called
* by bpf programs of types BPF_PROG_TYPE_LWT_IN and
* BPF_PROG_TYPE_LWT_XMIT.
* *
* A call to this helper is susceptible to change the underlaying * A call to this helper is susceptible to change the underlaying
* packet buffer. Therefore, at load time, all checks on pointers * packet buffer. Therefore, at load time, all checks on pointers
@ -2327,6 +2342,23 @@ union bpf_attr {
* "**y**". * "**y**".
* Return * Return
* 0 * 0
*
* struct bpf_sock *bpf_sk_fullsock(struct bpf_sock *sk)
* Description
* This helper gets a **struct bpf_sock** pointer such
* that all the fields in bpf_sock can be accessed.
* Return
* A **struct bpf_sock** pointer on success, or NULL in
* case of failure.
*
* struct bpf_tcp_sock *bpf_tcp_sock(struct bpf_sock *sk)
* Description
* This helper gets a **struct bpf_tcp_sock** pointer from a
* **struct bpf_sock** pointer.
*
* Return
* A **struct bpf_tcp_sock** pointer on success, or NULL in
* case of failure.
*/ */
#define __BPF_FUNC_MAPPER(FN) \ #define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \ FN(unspec), \
@ -2421,7 +2453,11 @@ union bpf_attr {
FN(map_peek_elem), \ FN(map_peek_elem), \
FN(msg_push_data), \ FN(msg_push_data), \
FN(msg_pop_data), \ FN(msg_pop_data), \
FN(rc_pointer_rel), FN(rc_pointer_rel), \
FN(spin_lock), \
FN(spin_unlock), \
FN(sk_fullsock), \
FN(tcp_sock),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper /* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call * function eBPF program intends to call
@ -2494,7 +2530,8 @@ enum bpf_hdr_start_off {
/* Encapsulation type for BPF_FUNC_lwt_push_encap helper. */ /* Encapsulation type for BPF_FUNC_lwt_push_encap helper. */
enum bpf_lwt_encap_mode { enum bpf_lwt_encap_mode {
BPF_LWT_ENCAP_SEG6, BPF_LWT_ENCAP_SEG6,
BPF_LWT_ENCAP_SEG6_INLINE BPF_LWT_ENCAP_SEG6_INLINE,
BPF_LWT_ENCAP_IP,
}; };
#define __bpf_md_ptr(type, name) \ #define __bpf_md_ptr(type, name) \
@ -2540,6 +2577,8 @@ struct __sk_buff {
__bpf_md_ptr(struct bpf_flow_keys *, flow_keys); __bpf_md_ptr(struct bpf_flow_keys *, flow_keys);
__u64 tstamp; __u64 tstamp;
__u32 wire_len; __u32 wire_len;
__u32 gso_segs;
__bpf_md_ptr(struct bpf_sock *, sk);
}; };
struct bpf_tunnel_key { struct bpf_tunnel_key {
@ -2581,7 +2620,15 @@ enum bpf_ret_code {
BPF_DROP = 2, BPF_DROP = 2,
/* 3-6 reserved */ /* 3-6 reserved */
BPF_REDIRECT = 7, BPF_REDIRECT = 7,
/* >127 are reserved for prog type specific return codes */ /* >127 are reserved for prog type specific return codes.
*
* BPF_LWT_REROUTE: used by BPF_PROG_TYPE_LWT_IN and
* BPF_PROG_TYPE_LWT_XMIT to indicate that skb had been
* changed and should be routed based on its new L3 header.
* (This is an L3 redirect, as opposed to L2 redirect
* represented by BPF_REDIRECT above).
*/
BPF_LWT_REROUTE = 128,
}; };
struct bpf_sock { struct bpf_sock {
@ -2591,14 +2638,52 @@ struct bpf_sock {
__u32 protocol; __u32 protocol;
__u32 mark; __u32 mark;
__u32 priority; __u32 priority;
__u32 src_ip4; /* Allows 1,2,4-byte read. /* IP address also allows 1 and 2 bytes access */
* Stored in network byte order. __u32 src_ip4;
__u32 src_ip6[4];
__u32 src_port; /* host byte order */
__u32 dst_port; /* network byte order */
__u32 dst_ip4;
__u32 dst_ip6[4];
__u32 state;
};
struct bpf_tcp_sock {
__u32 snd_cwnd; /* Sending congestion window */
__u32 srtt_us; /* smoothed round trip time << 3 in usecs */
__u32 rtt_min;
__u32 snd_ssthresh; /* Slow start size threshold */
__u32 rcv_nxt; /* What we want to receive next */
__u32 snd_nxt; /* Next sequence we send */
__u32 snd_una; /* First byte we want an ack for */
__u32 mss_cache; /* Cached effective mss, not including SACKS */
__u32 ecn_flags; /* ECN status bits. */
__u32 rate_delivered; /* saved rate sample: packets delivered */
__u32 rate_interval_us; /* saved rate sample: time elapsed */
__u32 packets_out; /* Packets which are "in flight" */
__u32 retrans_out; /* Retransmitted packets out */
__u32 total_retrans; /* Total retransmits for entire connection */
__u32 segs_in; /* RFC4898 tcpEStatsPerfSegsIn
* total number of segments in.
*/ */
__u32 src_ip6[4]; /* Allows 1,2,4-byte read. __u32 data_segs_in; /* RFC4898 tcpEStatsPerfDataSegsIn
* Stored in network byte order. * total number of data segments in.
*/ */
__u32 src_port; /* Allows 4-byte read. __u32 segs_out; /* RFC4898 tcpEStatsPerfSegsOut
* Stored in host byte order * The total number of segments sent.
*/
__u32 data_segs_out; /* RFC4898 tcpEStatsPerfDataSegsOut
* total number of data segments sent.
*/
__u32 lost_out; /* Lost packets */
__u32 sacked_out; /* SACK'd packets */
__u64 bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived
* sum(delta(rcv_nxt)), or how many bytes
* were acked.
*/
__u64 bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked
* sum(delta(snd_una)), or how many bytes
* were acked.
*/ */
}; };
@ -3054,4 +3139,7 @@ struct bpf_line_info {
__u32 line_col; __u32 line_col;
}; };
struct bpf_spin_lock {
__u32 val;
};
#endif /* __LINUX_BPF_H__ */ #endif /* __LINUX_BPF_H__ */

View File

@ -89,6 +89,22 @@ enum devlink_command {
DEVLINK_CMD_REGION_DEL, DEVLINK_CMD_REGION_DEL,
DEVLINK_CMD_REGION_READ, DEVLINK_CMD_REGION_READ,
DEVLINK_CMD_PORT_PARAM_GET, /* can dump */
DEVLINK_CMD_PORT_PARAM_SET,
DEVLINK_CMD_PORT_PARAM_NEW,
DEVLINK_CMD_PORT_PARAM_DEL,
DEVLINK_CMD_INFO_GET, /* can dump */
DEVLINK_CMD_HEALTH_REPORTER_GET,
DEVLINK_CMD_HEALTH_REPORTER_SET,
DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
DEVLINK_CMD_FLASH_UPDATE,
/* add new commands above here */ /* add new commands above here */
__DEVLINK_CMD_MAX, __DEVLINK_CMD_MAX,
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
@ -285,6 +301,37 @@ enum devlink_attr {
DEVLINK_ATTR_REGION_CHUNK_ADDR, /* u64 */ DEVLINK_ATTR_REGION_CHUNK_ADDR, /* u64 */
DEVLINK_ATTR_REGION_CHUNK_LEN, /* u64 */ DEVLINK_ATTR_REGION_CHUNK_LEN, /* u64 */
DEVLINK_ATTR_INFO_DRIVER_NAME, /* string */
DEVLINK_ATTR_INFO_SERIAL_NUMBER, /* string */
DEVLINK_ATTR_INFO_VERSION_FIXED, /* nested */
DEVLINK_ATTR_INFO_VERSION_RUNNING, /* nested */
DEVLINK_ATTR_INFO_VERSION_STORED, /* nested */
DEVLINK_ATTR_INFO_VERSION_NAME, /* string */
DEVLINK_ATTR_INFO_VERSION_VALUE, /* string */
DEVLINK_ATTR_SB_POOL_CELL_SIZE, /* u32 */
DEVLINK_ATTR_FMSG, /* nested */
DEVLINK_ATTR_FMSG_OBJ_NEST_START, /* flag */
DEVLINK_ATTR_FMSG_PAIR_NEST_START, /* flag */
DEVLINK_ATTR_FMSG_ARR_NEST_START, /* flag */
DEVLINK_ATTR_FMSG_NEST_END, /* flag */
DEVLINK_ATTR_FMSG_OBJ_NAME, /* string */
DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE, /* u8 */
DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA, /* dynamic */
DEVLINK_ATTR_HEALTH_REPORTER, /* nested */
DEVLINK_ATTR_HEALTH_REPORTER_NAME, /* string */
DEVLINK_ATTR_HEALTH_REPORTER_STATE, /* u8 */
DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT, /* u64 */
DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT, /* u64 */
DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS, /* u64 */
DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD, /* u64 */
DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER, /* u8 */
DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME, /* string */
DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, /* string */
/* add new attributes above here, update the policy in devlink.c */ /* add new attributes above here, update the policy in devlink.c */
__DEVLINK_ATTR_MAX, __DEVLINK_ATTR_MAX,

View File

@ -108,6 +108,8 @@ struct icmp6hdr {
#define ICMPV6_MOBILE_PREFIX_SOL 146 #define ICMPV6_MOBILE_PREFIX_SOL 146
#define ICMPV6_MOBILE_PREFIX_ADV 147 #define ICMPV6_MOBILE_PREFIX_ADV 147
#define ICMPV6_MRDISC_ADV 151
/* /*
* Codes for Destination Unreachable * Codes for Destination Unreachable
*/ */

View File

@ -117,6 +117,30 @@ struct ad_info {
__u8 partner_system[ETH_ALEN]; __u8 partner_system[ETH_ALEN];
}; };
/* Embedded inside LINK_XSTATS_TYPE_BOND */
enum {
BOND_XSTATS_UNSPEC,
BOND_XSTATS_3AD,
__BOND_XSTATS_MAX
};
#define BOND_XSTATS_MAX (__BOND_XSTATS_MAX - 1)
/* Embedded inside BOND_XSTATS_3AD */
enum {
BOND_3AD_STAT_LACPDU_RX,
BOND_3AD_STAT_LACPDU_TX,
BOND_3AD_STAT_LACPDU_UNKNOWN_RX,
BOND_3AD_STAT_LACPDU_ILLEGAL_RX,
BOND_3AD_STAT_MARKER_RX,
BOND_3AD_STAT_MARKER_TX,
BOND_3AD_STAT_MARKER_RESP_RX,
BOND_3AD_STAT_MARKER_RESP_TX,
BOND_3AD_STAT_MARKER_UNKNOWN_RX,
BOND_3AD_STAT_PAD,
__BOND_3AD_STAT_MAX
};
#define BOND_3AD_STAT_MAX (__BOND_3AD_STAT_MAX - 1)
#endif /* _LINUX_IF_BONDING_H */ #endif /* _LINUX_IF_BONDING_H */
/* /*

View File

@ -923,6 +923,7 @@ enum {
enum { enum {
LINK_XSTATS_TYPE_UNSPEC, LINK_XSTATS_TYPE_UNSPEC,
LINK_XSTATS_TYPE_BRIDGE, LINK_XSTATS_TYPE_BRIDGE,
LINK_XSTATS_TYPE_BOND,
__LINK_XSTATS_TYPE_MAX __LINK_XSTATS_TYPE_MAX
}; };
#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) #define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1)

View File

@ -292,10 +292,11 @@ struct sockaddr_in {
#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) #define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000)
/* Defines for Multicast INADDR */ /* Defines for Multicast INADDR */
#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */ #define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */
#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ #define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */
#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ #define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */
#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */ #define INADDR_ALLSNOOPERS_GROUP 0xe000006aU /* 224.0.0.106 */
#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */
#endif #endif
/* <asm/byteorder.h> contains the htonl type stuff.. */ /* <asm/byteorder.h> contains the htonl type stuff.. */

View File

@ -63,12 +63,49 @@ enum {
#define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2) #define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2)
#define TC_ACT_EXT_OPCODE_MAX TC_ACT_GOTO_CHAIN #define TC_ACT_EXT_OPCODE_MAX TC_ACT_GOTO_CHAIN
/* These macros are put here for binary compatibility with userspace apps that
* make use of them. For kernel code and new userspace apps, use the TCA_ID_*
* versions.
*/
#define TCA_ACT_GACT 5
#define TCA_ACT_IPT 6
#define TCA_ACT_PEDIT 7
#define TCA_ACT_MIRRED 8
#define TCA_ACT_NAT 9
#define TCA_ACT_XT 10
#define TCA_ACT_SKBEDIT 11
#define TCA_ACT_VLAN 12
#define TCA_ACT_BPF 13
#define TCA_ACT_CONNMARK 14
#define TCA_ACT_SKBMOD 15
#define TCA_ACT_CSUM 16
#define TCA_ACT_TUNNEL_KEY 17
#define TCA_ACT_SIMP 22
#define TCA_ACT_IFE 25
#define TCA_ACT_SAMPLE 26
/* Action type identifiers*/ /* Action type identifiers*/
enum { enum tca_id {
TCA_ID_UNSPEC=0, TCA_ID_UNSPEC = 0,
TCA_ID_POLICE=1, TCA_ID_POLICE = 1,
TCA_ID_GACT = TCA_ACT_GACT,
TCA_ID_IPT = TCA_ACT_IPT,
TCA_ID_PEDIT = TCA_ACT_PEDIT,
TCA_ID_MIRRED = TCA_ACT_MIRRED,
TCA_ID_NAT = TCA_ACT_NAT,
TCA_ID_XT = TCA_ACT_XT,
TCA_ID_SKBEDIT = TCA_ACT_SKBEDIT,
TCA_ID_VLAN = TCA_ACT_VLAN,
TCA_ID_BPF = TCA_ACT_BPF,
TCA_ID_CONNMARK = TCA_ACT_CONNMARK,
TCA_ID_SKBMOD = TCA_ACT_SKBMOD,
TCA_ID_CSUM = TCA_ACT_CSUM,
TCA_ID_TUNNEL_KEY = TCA_ACT_TUNNEL_KEY,
TCA_ID_SIMP = TCA_ACT_SIMP,
TCA_ID_IFE = TCA_ACT_IFE,
TCA_ID_SAMPLE = TCA_ACT_SAMPLE,
/* other actions go here */ /* other actions go here */
__TCA_ID_MAX=255 __TCA_ID_MAX = 255
}; };
#define TCA_ID_MAX __TCA_ID_MAX #define TCA_ID_MAX __TCA_ID_MAX
@ -333,12 +370,19 @@ enum {
/* Basic filter */ /* Basic filter */
struct tc_basic_pcnt {
__u64 rcnt;
__u64 rhit;
};
enum { enum {
TCA_BASIC_UNSPEC, TCA_BASIC_UNSPEC,
TCA_BASIC_CLASSID, TCA_BASIC_CLASSID,
TCA_BASIC_EMATCHES, TCA_BASIC_EMATCHES,
TCA_BASIC_ACT, TCA_BASIC_ACT,
TCA_BASIC_POLICE, TCA_BASIC_POLICE,
TCA_BASIC_PCNT,
TCA_BASIC_PAD,
__TCA_BASIC_MAX __TCA_BASIC_MAX
}; };
@ -527,11 +571,17 @@ enum {
/* Match-all classifier */ /* Match-all classifier */
struct tc_matchall_pcnt {
__u64 rhit;
};
enum { enum {
TCA_MATCHALL_UNSPEC, TCA_MATCHALL_UNSPEC,
TCA_MATCHALL_CLASSID, TCA_MATCHALL_CLASSID,
TCA_MATCHALL_ACT, TCA_MATCHALL_ACT,
TCA_MATCHALL_FLAGS, TCA_MATCHALL_FLAGS,
TCA_MATCHALL_PCNT,
TCA_MATCHALL_PAD,
__TCA_MATCHALL_MAX, __TCA_MATCHALL_MAX,
}; };

View File

@ -954,7 +954,7 @@ enum {
#define TCA_PIE_MAX (__TCA_PIE_MAX - 1) #define TCA_PIE_MAX (__TCA_PIE_MAX - 1)
struct tc_pie_xstats { struct tc_pie_xstats {
__u32 prob; /* current probability */ __u64 prob; /* current probability */
__u32 delay; /* current delay in ms */ __u32 delay; /* current delay in ms */
__u32 avg_dq_rate; /* current average dq_rate in bits/pie_time */ __u32 avg_dq_rate; /* current average dq_rate in bits/pie_time */
__u32 packets_in; /* total number of packets enqueued */ __u32 packets_in; /* total number of packets enqueued */

View File

@ -59,6 +59,10 @@
typedef __s32 sctp_assoc_t; typedef __s32 sctp_assoc_t;
#define SCTP_FUTURE_ASSOC 0
#define SCTP_CURRENT_ASSOC 1
#define SCTP_ALL_ASSOC 2
/* The following symbols come from the Sockets API Extensions for /* The following symbols come from the Sockets API Extensions for
* SCTP <draft-ietf-tsvwg-sctpsocket-07.txt>. * SCTP <draft-ietf-tsvwg-sctpsocket-07.txt>.
*/ */

View File

@ -13,8 +13,6 @@
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_BPF 13
struct tc_act_bpf { struct tc_act_bpf {
tc_gen; tc_gen;
}; };

View File

@ -5,8 +5,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_CONNMARK 14
struct tc_connmark { struct tc_connmark {
tc_gen; tc_gen;
__u16 zone; __u16 zone;

View File

@ -5,8 +5,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_CSUM 16
enum { enum {
TCA_CSUM_UNSPEC, TCA_CSUM_UNSPEC,
TCA_CSUM_PARMS, TCA_CSUM_PARMS,

View File

@ -5,7 +5,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_GACT 5
struct tc_gact { struct tc_gact {
tc_gen; tc_gen;

View File

@ -6,7 +6,6 @@
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#include <linux/ife.h> #include <linux/ife.h>
#define TCA_ACT_IFE 25
/* Flag bits for now just encoding/decoding; mutually exclusive */ /* Flag bits for now just encoding/decoding; mutually exclusive */
#define IFE_ENCODE 1 #define IFE_ENCODE 1
#define IFE_DECODE 0 #define IFE_DECODE 0

View File

@ -4,9 +4,6 @@
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_IPT 6
#define TCA_ACT_XT 10
enum { enum {
TCA_IPT_UNSPEC, TCA_IPT_UNSPEC,
TCA_IPT_TABLE, TCA_IPT_TABLE,

View File

@ -5,7 +5,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_MIRRED 8
#define TCA_EGRESS_REDIR 1 /* packet redirect to EGRESS*/ #define TCA_EGRESS_REDIR 1 /* packet redirect to EGRESS*/
#define TCA_EGRESS_MIRROR 2 /* mirror packet to EGRESS */ #define TCA_EGRESS_MIRROR 2 /* mirror packet to EGRESS */
#define TCA_INGRESS_REDIR 3 /* packet redirect to INGRESS*/ #define TCA_INGRESS_REDIR 3 /* packet redirect to INGRESS*/

View File

@ -5,8 +5,6 @@
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#include <linux/types.h> #include <linux/types.h>
#define TCA_ACT_NAT 9
enum { enum {
TCA_NAT_UNSPEC, TCA_NAT_UNSPEC,
TCA_NAT_PARMS, TCA_NAT_PARMS,

View File

@ -5,8 +5,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_PEDIT 7
enum { enum {
TCA_PEDIT_UNSPEC, TCA_PEDIT_UNSPEC,
TCA_PEDIT_TM, TCA_PEDIT_TM,

View File

@ -6,8 +6,6 @@
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#define TCA_ACT_SAMPLE 26
struct tc_sample { struct tc_sample {
tc_gen; tc_gen;
}; };

View File

@ -23,8 +23,6 @@
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_SKBEDIT 11
#define SKBEDIT_F_PRIORITY 0x1 #define SKBEDIT_F_PRIORITY 0x1
#define SKBEDIT_F_QUEUE_MAPPING 0x2 #define SKBEDIT_F_QUEUE_MAPPING 0x2
#define SKBEDIT_F_MARK 0x4 #define SKBEDIT_F_MARK 0x4

View File

@ -13,8 +13,6 @@
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_SKBMOD 15
#define SKBMOD_F_DMAC 0x1 #define SKBMOD_F_DMAC 0x1
#define SKBMOD_F_SMAC 0x2 #define SKBMOD_F_SMAC 0x2
#define SKBMOD_F_ETYPE 0x4 #define SKBMOD_F_ETYPE 0x4

View File

@ -14,8 +14,6 @@
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_TUNNEL_KEY 17
#define TCA_TUNNEL_KEY_ACT_SET 1 #define TCA_TUNNEL_KEY_ACT_SET 1
#define TCA_TUNNEL_KEY_ACT_RELEASE 2 #define TCA_TUNNEL_KEY_ACT_RELEASE 2

View File

@ -13,8 +13,6 @@
#include <linux/pkt_cls.h> #include <linux/pkt_cls.h>
#define TCA_ACT_VLAN 12
#define TCA_VLAN_ACT_POP 1 #define TCA_VLAN_ACT_POP 1
#define TCA_VLAN_ACT_PUSH 2 #define TCA_VLAN_ACT_PUSH 2
#define TCA_VLAN_ACT_MODIFY 3 #define TCA_VLAN_ACT_MODIFY 3

View File

@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* xdp_diag: interface for query/monitor XDP sockets
* Copyright(c) 2019 Intel Corporation.
*/
#ifndef _LINUX_XDP_DIAG_H
#define _LINUX_XDP_DIAG_H
#include <linux/types.h>
struct xdp_diag_req {
__u8 sdiag_family;
__u8 sdiag_protocol;
__u16 pad;
__u32 xdiag_ino;
__u32 xdiag_show;
__u32 xdiag_cookie[2];
};
struct xdp_diag_msg {
__u8 xdiag_family;
__u8 xdiag_type;
__u16 pad;
__u32 xdiag_ino;
__u32 xdiag_cookie[2];
};
#define XDP_SHOW_INFO (1 << 0) /* Basic information */
#define XDP_SHOW_RING_CFG (1 << 1)
#define XDP_SHOW_UMEM (1 << 2)
#define XDP_SHOW_MEMINFO (1 << 3)
enum {
XDP_DIAG_NONE,
XDP_DIAG_INFO,
XDP_DIAG_UID,
XDP_DIAG_RX_RING,
XDP_DIAG_TX_RING,
XDP_DIAG_UMEM,
XDP_DIAG_UMEM_FILL_RING,
XDP_DIAG_UMEM_COMPLETION_RING,
XDP_DIAG_MEMINFO,
__XDP_DIAG_MAX,
};
#define XDP_DIAG_MAX (__XDP_DIAG_MAX - 1)
struct xdp_diag_info {
__u32 ifindex;
__u32 queue_id;
};
struct xdp_diag_ring {
__u32 entries; /*num descs */
};
#define XDP_DU_F_ZEROCOPY (1 << 0)
struct xdp_diag_umem {
__u64 size;
__u32 id;
__u32 num_pages;
__u32 chunk_size;
__u32 headroom;
__u32 ifindex;
__u32 queue_id;
__u32 flags;
__u32 refs;
};
#endif /* _LINUX_XDP_DIAG_H */

View File

@ -127,6 +127,14 @@ struct dn_naddr
# define CLOCK_TAI 11 # define CLOCK_TAI 11
#endif #endif
#ifndef AF_XDP
# define AF_XDP 44
# if AF_MAX < 45
# undef AF_MAX
# define AF_MAX 45
# endif
#endif
__u32 get_addr32(const char *name); __u32 get_addr32(const char *name);
int get_addr_1(inet_prefix *dst, const char *arg, int family); int get_addr_1(inet_prefix *dst, const char *arg, int family);
int get_prefix_1(inet_prefix *dst, char *arg, int family); int get_prefix_1(inet_prefix *dst, char *arg, int family);

View File

@ -130,6 +130,9 @@ void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len);
int bridge_parse_xstats(struct link_util *lu, int argc, char **argv); int bridge_parse_xstats(struct link_util *lu, int argc, char **argv);
int bridge_print_xstats(struct nlmsghdr *n, void *arg); int bridge_print_xstats(struct nlmsghdr *n, void *arg);
int bond_parse_xstats(struct link_util *lu, int argc, char **argv);
int bond_print_xstats(struct nlmsghdr *n, void *arg);
/* iproute_lwtunnel.c */ /* iproute_lwtunnel.c */
int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp); int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp);
void lwt_print_encap(FILE *fp, struct rtattr *encap_type, struct rtattr *encap); void lwt_print_encap(FILE *fp, struct rtattr *encap_type, struct rtattr *encap);

View File

@ -237,9 +237,9 @@ static void print_tunnel(const struct l2tp_data *data)
print_string(PRINT_FP, NULL, print_string(PRINT_FP, NULL,
" UDP source / dest ports:", NULL); " UDP source / dest ports:", NULL);
print_uint(PRINT_ANY, "local_port", " %hu", print_hu(PRINT_ANY, "local_port", " %hu",
p->local_udp_port); p->local_udp_port);
print_uint(PRINT_ANY, "peer_port", "/%hu", print_hu(PRINT_ANY, "peer_port", "/%hu",
p->peer_udp_port); p->peer_udp_port);
print_nl(); print_nl();

View File

@ -1083,6 +1083,9 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
if (rtnl_talk(&rth, &req.n, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL) < 0)
return -2; return -2;
/* remove device from cache; next use can refresh with new data */
ll_drop_by_index(req.i.ifi_index);
return 0; return 0;
} }

View File

@ -13,16 +13,18 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <linux/if_link.h> #include <linux/if_bonding.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include "rt_names.h" #include "rt_names.h"
#include "utils.h" #include "utils.h"
#include "ip_common.h" #include "ip_common.h"
#include "json_print.h"
#define BOND_MAX_ARP_TARGETS 16 #define BOND_MAX_ARP_TARGETS 16
static unsigned int xstats_print_attr;
static int filter_index;
static const char *mode_tbl[] = { static const char *mode_tbl[] = {
"balance-rr", "balance-rr",
"active-backup", "active-backup",
@ -649,10 +651,169 @@ static void bond_print_help(struct link_util *lu, int argc, char **argv,
print_explain(f); print_explain(f);
} }
static void bond_print_xstats_help(struct link_util *lu, FILE *f)
{
fprintf(f, "Usage: ... %s [ 802.3ad ] [ dev DEVICE ]\n", lu->id);
}
static void bond_print_3ad_stats(struct rtattr *lacpattr)
{
struct rtattr *lacptb[BOND_3AD_STAT_MAX+1];
__u64 val;
parse_rtattr(lacptb, BOND_3AD_STAT_MAX, RTA_DATA(lacpattr),
RTA_PAYLOAD(lacpattr));
open_json_object("802.3ad");
if (lacptb[BOND_3AD_STAT_LACPDU_RX]) {
print_string(PRINT_FP, NULL, "%-16s ", "");
print_u64(PRINT_ANY, "lacpdu_rx", "LACPDU Rx %llu\n",
rta_getattr_u64(lacptb[BOND_3AD_STAT_LACPDU_RX]));
}
if (lacptb[BOND_3AD_STAT_LACPDU_TX]) {
print_string(PRINT_FP, NULL, "%-16s ", "");
print_u64(PRINT_ANY, "lacpdu_tx", "LACPDU Tx %llu\n",
rta_getattr_u64(lacptb[BOND_3AD_STAT_LACPDU_TX]));
}
if (lacptb[BOND_3AD_STAT_LACPDU_UNKNOWN_RX]) {
print_string(PRINT_FP, NULL, "%-16s ", "");
val = rta_getattr_u64(lacptb[BOND_3AD_STAT_LACPDU_UNKNOWN_RX]);
print_u64(PRINT_ANY,
"lacpdu_unknown_rx",
"LACPDU Unknown type Rx %llu\n",
val);
}
if (lacptb[BOND_3AD_STAT_LACPDU_ILLEGAL_RX]) {
print_string(PRINT_FP, NULL, "%-16s ", "");
val = rta_getattr_u64(lacptb[BOND_3AD_STAT_LACPDU_ILLEGAL_RX]);
print_u64(PRINT_ANY,
"lacpdu_illegal_rx",
"LACPDU Illegal Rx %llu\n",
val);
}
if (lacptb[BOND_3AD_STAT_MARKER_RX]) {
print_string(PRINT_FP, NULL, "%-16s ", "");
print_u64(PRINT_ANY, "marker_rx", "Marker Rx %llu\n",
rta_getattr_u64(lacptb[BOND_3AD_STAT_MARKER_RX]));
}
if (lacptb[BOND_3AD_STAT_MARKER_TX]) {
print_string(PRINT_FP, NULL, "%-16s ", "");
print_u64(PRINT_ANY, "marker_tx", "Marker Tx %llu\n",
rta_getattr_u64(lacptb[BOND_3AD_STAT_MARKER_TX]));
}
if (lacptb[BOND_3AD_STAT_MARKER_RESP_RX]) {
print_string(PRINT_FP, NULL, "%-16s ", "");
val = rta_getattr_u64(lacptb[BOND_3AD_STAT_MARKER_RESP_RX]);
print_u64(PRINT_ANY,
"marker_response_rx",
"Marker response Rx %llu\n",
val);
}
if (lacptb[BOND_3AD_STAT_MARKER_RESP_TX]) {
print_string(PRINT_FP, NULL, "%-16s ", "");
val = rta_getattr_u64(lacptb[BOND_3AD_STAT_MARKER_RESP_TX]);
print_u64(PRINT_ANY,
"marker_response_tx",
"Marker response Tx %llu\n",
val);
}
if (lacptb[BOND_3AD_STAT_MARKER_UNKNOWN_RX]) {
print_string(PRINT_FP, NULL, "%-16s ", "");
val = rta_getattr_u64(lacptb[BOND_3AD_STAT_MARKER_UNKNOWN_RX]);
print_u64(PRINT_ANY,
"marker_unknown_rx",
"Marker unknown type Rx %llu\n",
val);
}
close_json_object();
}
static void bond_print_stats_attr(struct rtattr *attr, int ifindex)
{
struct rtattr *bondtb[LINK_XSTATS_TYPE_MAX+1];
struct rtattr *i, *list;
const char *ifname = "";
int rem;
parse_rtattr(bondtb, LINK_XSTATS_TYPE_MAX+1, RTA_DATA(attr),
RTA_PAYLOAD(attr));
if (!bondtb[LINK_XSTATS_TYPE_BOND])
return;
list = bondtb[LINK_XSTATS_TYPE_BOND];
rem = RTA_PAYLOAD(list);
open_json_object(NULL);
ifname = ll_index_to_name(ifindex);
print_string(PRINT_ANY, "ifname", "%-16s\n", ifname);
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
if (xstats_print_attr && i->rta_type != xstats_print_attr)
continue;
switch (i->rta_type) {
case BOND_XSTATS_3AD:
bond_print_3ad_stats(i);
break;
}
break;
}
close_json_object();
}
int bond_print_xstats(struct nlmsghdr *n, void *arg)
{
struct if_stats_msg *ifsm = NLMSG_DATA(n);
struct rtattr *tb[IFLA_STATS_MAX+1];
int len = n->nlmsg_len;
len -= NLMSG_LENGTH(sizeof(*ifsm));
if (len < 0) {
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
return -1;
}
if (filter_index && filter_index != ifsm->ifindex)
return 0;
parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
if (tb[IFLA_STATS_LINK_XSTATS])
bond_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
ifsm->ifindex);
if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
bond_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
ifsm->ifindex);
return 0;
}
int bond_parse_xstats(struct link_util *lu, int argc, char **argv)
{
while (argc > 0) {
if (strcmp(*argv, "lacp") == 0 ||
strcmp(*argv, "802.3ad") == 0) {
xstats_print_attr = BOND_XSTATS_3AD;
} else if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
filter_index = ll_name_to_index(*argv);
if (!filter_index)
return nodev(*argv);
} else if (strcmp(*argv, "help") == 0) {
bond_print_xstats_help(lu, stdout);
exit(0);
} else {
invarg("unknown attribute", *argv);
}
argc--; argv++;
}
return 0;
}
struct link_util bond_link_util = { struct link_util bond_link_util = {
.id = "bond", .id = "bond",
.maxattr = IFLA_BOND_MAX, .maxattr = IFLA_BOND_MAX,
.parse_opt = bond_parse_opt, .parse_opt = bond_parse_opt,
.print_opt = bond_print_opt, .print_opt = bond_print_opt,
.print_help = bond_print_help, .print_help = bond_print_help,
.parse_ifla_xstats = bond_parse_xstats,
.print_ifla_xstats = bond_print_xstats,
}; };

View File

@ -156,4 +156,6 @@ struct link_util bond_slave_link_util = {
.print_opt = bond_slave_print_opt, .print_opt = bond_slave_print_opt,
.parse_opt = bond_slave_parse_opt, .parse_opt = bond_slave_parse_opt,
.print_help = bond_slave_print_help, .print_help = bond_slave_print_help,
.parse_ifla_xstats = bond_parse_xstats,
.print_ifla_xstats = bond_print_xstats,
}; };

View File

@ -670,7 +670,7 @@ static void bridge_print_xstats_help(struct link_util *lu, FILE *f)
fprintf(f, "Usage: ... %s [ igmp ] [ dev DEVICE ]\n", lu->id); fprintf(f, "Usage: ... %s [ igmp ] [ dev DEVICE ]\n", lu->id);
} }
static void bridge_print_stats_attr(FILE *f, struct rtattr *attr, int ifindex) static void bridge_print_stats_attr(struct rtattr *attr, int ifindex)
{ {
struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1]; struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
struct br_mcast_stats *mstats; struct br_mcast_stats *mstats;
@ -685,76 +685,116 @@ static void bridge_print_stats_attr(FILE *f, struct rtattr *attr, int ifindex)
list = brtb[LINK_XSTATS_TYPE_BRIDGE]; list = brtb[LINK_XSTATS_TYPE_BRIDGE];
rem = RTA_PAYLOAD(list); rem = RTA_PAYLOAD(list);
open_json_object(NULL);
ifname = ll_index_to_name(ifindex);
print_string(PRINT_ANY, "ifname", "%-16s\n", ifname);
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
if (xstats_print_attr && i->rta_type != xstats_print_attr) if (xstats_print_attr && i->rta_type != xstats_print_attr)
continue; continue;
switch (i->rta_type) { switch (i->rta_type) {
case BRIDGE_XSTATS_MCAST: case BRIDGE_XSTATS_MCAST:
mstats = RTA_DATA(i); mstats = RTA_DATA(i);
ifname = ll_index_to_name(ifindex); open_json_object("multicast");
fprintf(f, "%-16s\n", ifname); open_json_object("igmp_queries");
fprintf(f, "%-16s IGMP queries:\n", ""); print_string(PRINT_FP, NULL,
fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n", "%-16s IGMP queries:\n", "");
"", print_string(PRINT_FP, NULL, "%-16s ", "");
mstats->igmp_v1queries[BR_MCAST_DIR_RX], print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
mstats->igmp_v2queries[BR_MCAST_DIR_RX], mstats->igmp_v1queries[BR_MCAST_DIR_RX]);
mstats->igmp_v3queries[BR_MCAST_DIR_RX]); print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n", mstats->igmp_v2queries[BR_MCAST_DIR_RX]);
"", print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
mstats->igmp_v1queries[BR_MCAST_DIR_TX], mstats->igmp_v3queries[BR_MCAST_DIR_RX]);
mstats->igmp_v2queries[BR_MCAST_DIR_TX], print_string(PRINT_FP, NULL, "%-16s ", "");
mstats->igmp_v3queries[BR_MCAST_DIR_TX]); print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
mstats->igmp_v1queries[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v2", "v2 %llu ",
mstats->igmp_v2queries[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
mstats->igmp_v3queries[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s IGMP reports:\n", ""); open_json_object("igmp_reports");
fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n", print_string(PRINT_FP, NULL,
"", "%-16s IGMP reports:\n", "");
mstats->igmp_v1reports[BR_MCAST_DIR_RX], print_string(PRINT_FP, NULL, "%-16s ", "");
mstats->igmp_v2reports[BR_MCAST_DIR_RX], print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
mstats->igmp_v3reports[BR_MCAST_DIR_RX]); mstats->igmp_v1reports[BR_MCAST_DIR_RX]);
fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n", print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
"", mstats->igmp_v2reports[BR_MCAST_DIR_RX]);
mstats->igmp_v1reports[BR_MCAST_DIR_TX], print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
mstats->igmp_v2reports[BR_MCAST_DIR_TX], mstats->igmp_v3reports[BR_MCAST_DIR_RX]);
mstats->igmp_v3reports[BR_MCAST_DIR_TX]); print_string(PRINT_FP, NULL, "%-16s ", "");
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
mstats->igmp_v1reports[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v2", "v2 %llu",
mstats->igmp_v2reports[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
mstats->igmp_v3reports[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s IGMP leaves: RX: %llu TX: %llu\n", open_json_object("igmp_leaves");
"", print_string(PRINT_FP, NULL,
mstats->igmp_leaves[BR_MCAST_DIR_RX], "%-16s IGMP leaves: ", "");
mstats->igmp_leaves[BR_MCAST_DIR_TX]); print_u64(PRINT_ANY, "rx", "RX: %llu ",
mstats->igmp_leaves[BR_MCAST_DIR_RX]);
print_u64(PRINT_ANY, "tx", "TX: %llu\n",
mstats->igmp_leaves[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s IGMP parse errors: %llu\n", print_string(PRINT_FP, NULL,
"", mstats->igmp_parse_errors); "%-16s IGMP parse errors: ", "");
print_u64(PRINT_ANY, "igmp_parse_errors", "%llu\n",
mstats->igmp_parse_errors);
fprintf(f, "%-16s MLD queries:\n", ""); open_json_object("mld_queries");
fprintf(f, "%-16s RX: v1 %llu v2 %llu\n", print_string(PRINT_FP, NULL,
"", "%-16s MLD queries:\n", "");
mstats->mld_v1queries[BR_MCAST_DIR_RX], print_string(PRINT_FP, NULL, "%-16s ", "");
mstats->mld_v2queries[BR_MCAST_DIR_RX]); print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
fprintf(f, "%-16s TX: v1 %llu v2 %llu\n", mstats->mld_v1queries[BR_MCAST_DIR_RX]);
"", print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
mstats->mld_v1queries[BR_MCAST_DIR_TX], mstats->mld_v2queries[BR_MCAST_DIR_RX]);
mstats->mld_v2queries[BR_MCAST_DIR_TX]); print_string(PRINT_FP, NULL, "%-16s ", "");
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
mstats->mld_v1queries[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v2", "v2 %llu\n",
mstats->mld_v2queries[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s MLD reports:\n", ""); open_json_object("mld_reports");
fprintf(f, "%-16s RX: v1 %llu v2 %llu\n", print_string(PRINT_FP, NULL,
"", "%-16s MLD reports:\n", "");
mstats->mld_v1reports[BR_MCAST_DIR_RX], print_string(PRINT_FP, NULL, "%-16s ", "");
mstats->mld_v2reports[BR_MCAST_DIR_RX]); print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
fprintf(f, "%-16s TX: v1 %llu v2 %llu\n", mstats->mld_v1reports[BR_MCAST_DIR_RX]);
"", print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
mstats->mld_v1reports[BR_MCAST_DIR_TX], mstats->mld_v2reports[BR_MCAST_DIR_RX]);
mstats->mld_v2reports[BR_MCAST_DIR_TX]); print_string(PRINT_FP, NULL, "%-16s ", "");
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
mstats->mld_v1reports[BR_MCAST_DIR_TX]);
print_u64(PRINT_ANY, "tx_v2", "v2 %llu\n",
mstats->mld_v2reports[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s MLD leaves: RX: %llu TX: %llu\n", open_json_object("mld_leaves");
"", print_string(PRINT_FP, NULL,
mstats->mld_leaves[BR_MCAST_DIR_RX], "%-16s MLD leaves: ", "");
mstats->mld_leaves[BR_MCAST_DIR_TX]); print_u64(PRINT_ANY, "rx", "RX: %llu ",
mstats->mld_leaves[BR_MCAST_DIR_RX]);
print_u64(PRINT_ANY, "tx", "TX: %llu\n",
mstats->mld_leaves[BR_MCAST_DIR_TX]);
close_json_object();
fprintf(f, "%-16s MLD parse errors: %llu\n", print_string(PRINT_FP, NULL,
"", mstats->mld_parse_errors); "%-16s MLD parse errors: ", "");
print_u64(PRINT_ANY, "mld_parse_errors", "%llu\n",
mstats->mld_parse_errors);
close_json_object();
break; break;
} }
} }
close_json_object();
} }
int bridge_print_xstats(struct nlmsghdr *n, void *arg) int bridge_print_xstats(struct nlmsghdr *n, void *arg)
@ -762,7 +802,6 @@ int bridge_print_xstats(struct nlmsghdr *n, void *arg)
struct if_stats_msg *ifsm = NLMSG_DATA(n); struct if_stats_msg *ifsm = NLMSG_DATA(n);
struct rtattr *tb[IFLA_STATS_MAX+1]; struct rtattr *tb[IFLA_STATS_MAX+1];
int len = n->nlmsg_len; int len = n->nlmsg_len;
FILE *fp = arg;
len -= NLMSG_LENGTH(sizeof(*ifsm)); len -= NLMSG_LENGTH(sizeof(*ifsm));
if (len < 0) { if (len < 0) {
@ -774,11 +813,11 @@ int bridge_print_xstats(struct nlmsghdr *n, void *arg)
parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len); parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
if (tb[IFLA_STATS_LINK_XSTATS]) if (tb[IFLA_STATS_LINK_XSTATS])
bridge_print_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS], bridge_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
ifsm->ifindex); ifsm->ifindex);
if (tb[IFLA_STATS_LINK_XSTATS_SLAVE]) if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
bridge_print_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE], bridge_print_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
ifsm->ifindex); ifsm->ifindex);
return 0; return 0;

View File

@ -70,10 +70,13 @@ int iplink_ifla_xstats(int argc, char **argv)
return -1; return -1;
} }
new_json_obj(json);
if (rtnl_dump_filter(&rth, lu->print_ifla_xstats, stdout) < 0) { if (rtnl_dump_filter(&rth, lu->print_ifla_xstats, stdout) < 0) {
delete_json_obj();
fprintf(stderr, "Dump terminated\n"); fprintf(stderr, "Dump terminated\n");
return -1; return -1;
} }
delete_json_obj();
return 0; return 0;
} }

View File

@ -28,6 +28,7 @@ static int usage(void)
{ {
fprintf(stderr, "Usage: ip netns list\n"); fprintf(stderr, "Usage: ip netns list\n");
fprintf(stderr, " ip netns add NAME\n"); fprintf(stderr, " ip netns add NAME\n");
fprintf(stderr, " ip netns attach NAME PID\n");
fprintf(stderr, " ip netns set NAME NETNSID\n"); fprintf(stderr, " ip netns set NAME NETNSID\n");
fprintf(stderr, " ip [-all] netns delete [NAME]\n"); fprintf(stderr, " ip [-all] netns delete [NAME]\n");
fprintf(stderr, " ip netns identify [PID]\n"); fprintf(stderr, " ip netns identify [PID]\n");
@ -632,24 +633,40 @@ static int create_netns_dir(void)
return 0; return 0;
} }
static int netns_add(int argc, char **argv) static int netns_add(int argc, char **argv, bool create)
{ {
/* This function creates a new network namespace and /* This function creates a new network namespace and
* a new mount namespace and bind them into a well known * a new mount namespace and bind them into a well known
* location in the filesystem based on the name provided. * location in the filesystem based on the name provided.
* *
* If create is true, a new namespace will be created,
* otherwise an existing one will be attached to the file.
*
* The mount namespace is created so that any necessary * The mount namespace is created so that any necessary
* userspace tweaks like remounting /sys, or bind mounting * userspace tweaks like remounting /sys, or bind mounting
* a new /etc/resolv.conf can be shared between uers. * a new /etc/resolv.conf can be shared between users.
*/ */
char netns_path[PATH_MAX]; char netns_path[PATH_MAX], proc_path[PATH_MAX];
const char *name; const char *name;
pid_t pid;
int fd; int fd;
int made_netns_run_dir_mount = 0; int made_netns_run_dir_mount = 0;
if (argc < 1) { if (create) {
fprintf(stderr, "No netns name specified\n"); if (argc < 1) {
return -1; fprintf(stderr, "No netns name specified\n");
return -1;
}
} else {
if (argc < 2) {
fprintf(stderr, "No netns name and PID specified\n");
return -1;
}
if (get_s32(&pid, argv[1], 0) || !pid) {
fprintf(stderr, "Invalid PID: %s\n", argv[1]);
return -1;
}
} }
name = argv[0]; name = argv[0];
@ -689,21 +706,33 @@ static int netns_add(int argc, char **argv)
return -1; return -1;
} }
close(fd); close(fd);
if (unshare(CLONE_NEWNET) < 0) {
fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n", if (create) {
name, strerror(errno)); if (unshare(CLONE_NEWNET) < 0) {
goto out_delete; fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
name, strerror(errno));
goto out_delete;
}
strcpy(proc_path, "/proc/self/ns/net");
} else {
snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid);
} }
/* Bind the netns last so I can watch for it */ /* Bind the netns last so I can watch for it */
if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) { if (mount(proc_path, netns_path, "none", MS_BIND, NULL) < 0) {
fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n", fprintf(stderr, "Bind %s -> %s failed: %s\n",
netns_path, strerror(errno)); proc_path, netns_path, strerror(errno));
goto out_delete; goto out_delete;
} }
return 0; return 0;
out_delete: out_delete:
netns_delete(argc, argv); if (create) {
netns_delete(argc, argv);
} else if (unlink(netns_path) < 0) {
fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
netns_path, strerror(errno));
}
return -1; return -1;
} }
@ -846,7 +875,7 @@ int do_netns(int argc, char **argv)
return usage(); return usage();
if (matches(*argv, "add") == 0) if (matches(*argv, "add") == 0)
return netns_add(argc-1, argv+1); return netns_add(argc-1, argv+1, true);
if (matches(*argv, "set") == 0) if (matches(*argv, "set") == 0)
return netns_set(argc-1, argv+1); return netns_set(argc-1, argv+1);
@ -866,6 +895,9 @@ int do_netns(int argc, char **argv)
if (matches(*argv, "monitor") == 0) if (matches(*argv, "monitor") == 0)
return netns_monitor(argc-1, argv+1); return netns_monitor(argc-1, argv+1);
if (matches(*argv, "attach") == 0)
return netns_add(argc-1, argv+1, false);
fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv); fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
exit(-1); exit(-1);
} }

View File

@ -497,7 +497,8 @@ void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
} }
static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len, static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
FILE *fp, const char *prefix, int newline) FILE *fp, const char *prefix, int newline,
bool nokeys)
{ {
int keylen; int keylen;
int i; int i;
@ -521,7 +522,9 @@ static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
goto fin; goto fin;
} }
if (keylen > 0) { if (nokeys)
fprintf(fp, "<<Keys hidden>>");
else if (keylen > 0) {
fprintf(fp, "0x"); fprintf(fp, "0x");
for (i = 0; i < keylen; i++) for (i = 0; i < keylen; i++)
fprintf(fp, "%.2x", (unsigned char)algo->alg_key[i]); fprintf(fp, "%.2x", (unsigned char)algo->alg_key[i]);
@ -536,13 +539,13 @@ static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
} }
static inline void xfrm_algo_print(struct xfrm_algo *algo, int type, int len, static inline void xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
FILE *fp, const char *prefix) FILE *fp, const char *prefix, bool nokeys)
{ {
return __xfrm_algo_print(algo, type, len, fp, prefix, 1); return __xfrm_algo_print(algo, type, len, fp, prefix, 1, nokeys);
} }
static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len, static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len,
FILE *fp, const char *prefix) FILE *fp, const char *prefix, bool nokeys)
{ {
struct xfrm_algo *base_algo = alloca(sizeof(*base_algo) + algo->alg_key_len / 8); struct xfrm_algo *base_algo = alloca(sizeof(*base_algo) + algo->alg_key_len / 8);
@ -550,7 +553,8 @@ static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len,
base_algo->alg_key_len = algo->alg_key_len; base_algo->alg_key_len = algo->alg_key_len;
memcpy(base_algo->alg_key, algo->alg_key, algo->alg_key_len / 8); memcpy(base_algo->alg_key, algo->alg_key, algo->alg_key_len / 8);
__xfrm_algo_print(base_algo, XFRMA_ALG_AEAD, len, fp, prefix, 0); __xfrm_algo_print(base_algo, XFRMA_ALG_AEAD, len, fp, prefix, 0,
nokeys);
fprintf(fp, " %d", algo->alg_icv_len); fprintf(fp, " %d", algo->alg_icv_len);
@ -558,7 +562,7 @@ static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len,
} }
static void xfrm_auth_trunc_print(struct xfrm_algo_auth *algo, int len, static void xfrm_auth_trunc_print(struct xfrm_algo_auth *algo, int len,
FILE *fp, const char *prefix) FILE *fp, const char *prefix, bool nokeys)
{ {
struct xfrm_algo *base_algo = alloca(sizeof(*base_algo) + algo->alg_key_len / 8); struct xfrm_algo *base_algo = alloca(sizeof(*base_algo) + algo->alg_key_len / 8);
@ -566,7 +570,8 @@ static void xfrm_auth_trunc_print(struct xfrm_algo_auth *algo, int len,
base_algo->alg_key_len = algo->alg_key_len; base_algo->alg_key_len = algo->alg_key_len;
memcpy(base_algo->alg_key, algo->alg_key, algo->alg_key_len / 8); memcpy(base_algo->alg_key, algo->alg_key, algo->alg_key_len / 8);
__xfrm_algo_print(base_algo, XFRMA_ALG_AUTH_TRUNC, len, fp, prefix, 0); __xfrm_algo_print(base_algo, XFRMA_ALG_AUTH_TRUNC, len, fp, prefix, 0,
nokeys);
fprintf(fp, " %d", algo->alg_trunc_len); fprintf(fp, " %d", algo->alg_trunc_len);
@ -679,7 +684,7 @@ done:
} }
void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
FILE *fp, const char *prefix) FILE *fp, const char *prefix, bool nokeys)
{ {
if (tb[XFRMA_MARK]) { if (tb[XFRMA_MARK]) {
struct rtattr *rta = tb[XFRMA_MARK]; struct rtattr *rta = tb[XFRMA_MARK];
@ -700,36 +705,36 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
if (tb[XFRMA_ALG_AUTH] && !tb[XFRMA_ALG_AUTH_TRUNC]) { if (tb[XFRMA_ALG_AUTH] && !tb[XFRMA_ALG_AUTH_TRUNC]) {
struct rtattr *rta = tb[XFRMA_ALG_AUTH]; struct rtattr *rta = tb[XFRMA_ALG_AUTH];
xfrm_algo_print(RTA_DATA(rta), xfrm_algo_print(RTA_DATA(rta), XFRMA_ALG_AUTH, RTA_PAYLOAD(rta),
XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix); fp, prefix, nokeys);
} }
if (tb[XFRMA_ALG_AUTH_TRUNC]) { if (tb[XFRMA_ALG_AUTH_TRUNC]) {
struct rtattr *rta = tb[XFRMA_ALG_AUTH_TRUNC]; struct rtattr *rta = tb[XFRMA_ALG_AUTH_TRUNC];
xfrm_auth_trunc_print(RTA_DATA(rta), xfrm_auth_trunc_print(RTA_DATA(rta), RTA_PAYLOAD(rta), fp,
RTA_PAYLOAD(rta), fp, prefix); prefix, nokeys);
} }
if (tb[XFRMA_ALG_AEAD]) { if (tb[XFRMA_ALG_AEAD]) {
struct rtattr *rta = tb[XFRMA_ALG_AEAD]; struct rtattr *rta = tb[XFRMA_ALG_AEAD];
xfrm_aead_print(RTA_DATA(rta), xfrm_aead_print(RTA_DATA(rta), RTA_PAYLOAD(rta), fp, prefix,
RTA_PAYLOAD(rta), fp, prefix); nokeys);
} }
if (tb[XFRMA_ALG_CRYPT]) { if (tb[XFRMA_ALG_CRYPT]) {
struct rtattr *rta = tb[XFRMA_ALG_CRYPT]; struct rtattr *rta = tb[XFRMA_ALG_CRYPT];
xfrm_algo_print(RTA_DATA(rta), xfrm_algo_print(RTA_DATA(rta), XFRMA_ALG_CRYPT,
XFRMA_ALG_CRYPT, RTA_PAYLOAD(rta), fp, prefix); RTA_PAYLOAD(rta), fp, prefix, nokeys);
} }
if (tb[XFRMA_ALG_COMP]) { if (tb[XFRMA_ALG_COMP]) {
struct rtattr *rta = tb[XFRMA_ALG_COMP]; struct rtattr *rta = tb[XFRMA_ALG_COMP];
xfrm_algo_print(RTA_DATA(rta), xfrm_algo_print(RTA_DATA(rta), XFRMA_ALG_COMP, RTA_PAYLOAD(rta),
XFRMA_ALG_COMP, RTA_PAYLOAD(rta), fp, prefix); fp, prefix, nokeys);
} }
if (tb[XFRMA_ENCAP]) { if (tb[XFRMA_ENCAP]) {
@ -897,7 +902,7 @@ static int xfrm_selector_iszero(struct xfrm_selector *s)
void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo, void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
struct rtattr *tb[], FILE *fp, const char *prefix, struct rtattr *tb[], FILE *fp, const char *prefix,
const char *title) const char *title, bool nokeys)
{ {
char buf[STRBUF_SIZE] = {}; char buf[STRBUF_SIZE] = {};
int force_spi = xfrm_xfrmproto_is_ipsec(xsinfo->id.proto); int force_spi = xfrm_xfrmproto_is_ipsec(xsinfo->id.proto);
@ -943,7 +948,7 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
fprintf(fp, " (0x%s)", strxf_mask8(xsinfo->flags)); fprintf(fp, " (0x%s)", strxf_mask8(xsinfo->flags));
fprintf(fp, "%s", _SL_); fprintf(fp, "%s", _SL_);
xfrm_xfrma_print(tb, xsinfo->family, fp, buf); xfrm_xfrma_print(tb, xsinfo->family, fp, buf, nokeys);
if (!xfrm_selector_iszero(&xsinfo->sel)) { if (!xfrm_selector_iszero(&xsinfo->sel)) {
char sbuf[STRBUF_SIZE]; char sbuf[STRBUF_SIZE];
@ -1071,7 +1076,7 @@ void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo,
if (show_stats > 0) if (show_stats > 0)
xfrm_lifetime_print(&xpinfo->lft, &xpinfo->curlft, fp, buf); xfrm_lifetime_print(&xpinfo->lft, &xpinfo->curlft, fp, buf);
xfrm_xfrma_print(tb, xpinfo->sel.family, fp, buf); xfrm_xfrma_print(tb, xpinfo->sel.family, fp, buf, false);
} }
int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family, int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family,

View File

@ -105,6 +105,7 @@ struct xfrm_filter {
extern struct xfrm_filter filter; extern struct xfrm_filter filter;
int xfrm_state_print(struct nlmsghdr *n, void *arg); int xfrm_state_print(struct nlmsghdr *n, void *arg);
int xfrm_state_print_nokeys(struct nlmsghdr *n, void *arg);
int xfrm_policy_print(struct nlmsghdr *n, void *arg); int xfrm_policy_print(struct nlmsghdr *n, void *arg);
int do_xfrm_state(int argc, char **argv); int do_xfrm_state(int argc, char **argv);
int do_xfrm_policy(int argc, char **argv); int do_xfrm_policy(int argc, char **argv);
@ -124,10 +125,10 @@ const char *strxf_ptype(__u8 ptype);
void xfrm_selector_print(struct xfrm_selector *sel, __u16 family, void xfrm_selector_print(struct xfrm_selector *sel, __u16 family,
FILE *fp, const char *prefix); FILE *fp, const char *prefix);
void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
FILE *fp, const char *prefix); FILE *fp, const char *prefix, bool nokeys);
void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo, void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
struct rtattr *tb[], FILE *fp, const char *prefix, struct rtattr *tb[], FILE *fp, const char *prefix,
const char *title); const char *title, bool nokeys);
void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo, void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo,
struct rtattr *tb[], FILE *fp, const char *prefix, struct rtattr *tb[], FILE *fp, const char *prefix,
const char *title); const char *title);

View File

@ -35,10 +35,11 @@
static void usage(void) __attribute__((noreturn)); static void usage(void) __attribute__((noreturn));
static int listen_all_nsid; static int listen_all_nsid;
static bool nokeys;
static void usage(void) static void usage(void)
{ {
fprintf(stderr, "Usage: ip xfrm monitor [all-nsid] [ all | OBJECTS | help ]\n"); fprintf(stderr, "Usage: ip xfrm monitor [ nokeys ] [ all-nsid ] [ all | OBJECTS | help ]\n");
fprintf(stderr, "OBJECTS := { acquire | expire | SA | aevent | policy | report }\n"); fprintf(stderr, "OBJECTS := { acquire | expire | SA | aevent | policy | report }\n");
exit(-1); exit(-1);
} }
@ -197,7 +198,7 @@ static int xfrm_report_print(struct nlmsghdr *n, void *arg)
parse_rtattr(tb, XFRMA_MAX, XFRMREP_RTA(xrep), len); parse_rtattr(tb, XFRMA_MAX, XFRMREP_RTA(xrep), len);
xfrm_xfrma_print(tb, family, fp, " "); xfrm_xfrma_print(tb, family, fp, " ", nokeys);
if (oneline) if (oneline)
fprintf(fp, "\n"); fprintf(fp, "\n");
@ -352,6 +353,8 @@ int do_xfrm_monitor(int argc, char **argv)
if (matches(*argv, "file") == 0) { if (matches(*argv, "file") == 0) {
NEXT_ARG(); NEXT_ARG();
file = *argv; file = *argv;
} else if (strcmp(*argv, "nokeys") == 0) {
nokeys = true;
} else if (strcmp(*argv, "all") == 0) { } else if (strcmp(*argv, "all") == 0) {
/* fall out */ /* fall out */
} else if (matches(*argv, "all-nsid") == 0) { } else if (matches(*argv, "all-nsid") == 0) {

View File

@ -65,7 +65,9 @@ static void usage(void)
fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ mark MARK [ mask MASK ] ]\n"); fprintf(stderr, "Usage: ip xfrm state allocspi ID [ mode MODE ] [ mark MARK [ mask MASK ] ]\n");
fprintf(stderr, " [ reqid REQID ] [ seq SEQ ] [ min SPI max SPI ]\n"); fprintf(stderr, " [ reqid REQID ] [ seq SEQ ] [ min SPI max SPI ]\n");
fprintf(stderr, "Usage: ip xfrm state { delete | get } ID [ mark MARK [ mask MASK ] ]\n"); fprintf(stderr, "Usage: ip xfrm state { delete | get } ID [ mark MARK [ mask MASK ] ]\n");
fprintf(stderr, "Usage: ip xfrm state { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n"); fprintf(stderr, "Usage: ip xfrm state deleteall [ ID ] [ mode MODE ] [ reqid REQID ]\n");
fprintf(stderr, " [ flag FLAG-LIST ]\n");
fprintf(stderr, "Usage: ip xfrm state list [ nokeys ] [ ID ] [ mode MODE ] [ reqid REQID ]\n");
fprintf(stderr, " [ flag FLAG-LIST ]\n"); fprintf(stderr, " [ flag FLAG-LIST ]\n");
fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM-PROTO ]\n"); fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM-PROTO ]\n");
fprintf(stderr, "Usage: ip xfrm state count\n"); fprintf(stderr, "Usage: ip xfrm state count\n");
@ -908,7 +910,7 @@ static int xfrm_state_filter_match(struct xfrm_usersa_info *xsinfo)
return 1; return 1;
} }
int xfrm_state_print(struct nlmsghdr *n, void *arg) static int __do_xfrm_state_print(struct nlmsghdr *n, void *arg, bool nokeys)
{ {
FILE *fp = (FILE *)arg; FILE *fp = (FILE *)arg;
struct rtattr *tb[XFRMA_MAX+1]; struct rtattr *tb[XFRMA_MAX+1];
@ -979,7 +981,7 @@ int xfrm_state_print(struct nlmsghdr *n, void *arg)
xsinfo = RTA_DATA(tb[XFRMA_SA]); xsinfo = RTA_DATA(tb[XFRMA_SA]);
} }
xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL); xfrm_state_info_print(xsinfo, tb, fp, NULL, NULL, nokeys);
if (n->nlmsg_type == XFRM_MSG_EXPIRE) { if (n->nlmsg_type == XFRM_MSG_EXPIRE) {
fprintf(fp, "\t"); fprintf(fp, "\t");
@ -994,6 +996,16 @@ int xfrm_state_print(struct nlmsghdr *n, void *arg)
return 0; return 0;
} }
int xfrm_state_print(struct nlmsghdr *n, void *arg)
{
return __do_xfrm_state_print(n, arg, false);
}
int xfrm_state_print_nokeys(struct nlmsghdr *n, void *arg)
{
return __do_xfrm_state_print(n, arg, true);
}
static int xfrm_state_get_or_delete(int argc, char **argv, int delete) static int xfrm_state_get_or_delete(int argc, char **argv, int delete)
{ {
struct rtnl_handle rth; struct rtnl_handle rth;
@ -1145,13 +1157,16 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
{ {
char *idp = NULL; char *idp = NULL;
struct rtnl_handle rth; struct rtnl_handle rth;
bool nokeys = false;
if (argc > 0) if (argc > 0)
filter.use = 1; filter.use = 1;
filter.xsinfo.family = preferred_family; filter.xsinfo.family = preferred_family;
while (argc > 0) { while (argc > 0) {
if (strcmp(*argv, "mode") == 0) { if (strcmp(*argv, "nokeys") == 0) {
nokeys = true;
} else if (strcmp(*argv, "mode") == 0) {
NEXT_ARG(); NEXT_ARG();
xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv); xfrm_mode_parse(&filter.xsinfo.mode, &argc, &argv);
@ -1267,7 +1282,9 @@ static int xfrm_state_list_or_deleteall(int argc, char **argv, int deleteall)
exit(1); exit(1);
} }
if (rtnl_dump_filter(&rth, xfrm_state_print, stdout) < 0) { rtnl_filter_t filter = nokeys ?
xfrm_state_print_nokeys : xfrm_state_print;
if (rtnl_dump_filter(&rth, filter, stdout) < 0) {
fprintf(stderr, "Dump terminated\n"); fprintf(stderr, "Dump terminated\n");
exit(1); exit(1);
} }

View File

@ -339,7 +339,7 @@ out:
return ret; return ret;
} }
void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len) void bpf_print_ops(struct rtattr *bpf_ops, __u16 len)
{ {
struct sock_filter *ops = RTA_DATA(bpf_ops); struct sock_filter *ops = RTA_DATA(bpf_ops);
int i; int i;
@ -347,14 +347,24 @@ void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len)
if (len == 0) if (len == 0)
return; return;
fprintf(f, "bytecode \'%u,", len); open_json_object("bytecode");
print_uint(PRINT_ANY, "length", "bytecode \'%u,", len);
open_json_array(PRINT_JSON, "insns");
for (i = 0; i < len - 1; i++) for (i = 0; i < len; i++) {
fprintf(f, "%hu %hhu %hhu %u,", ops[i].code, ops[i].jt, open_json_object(NULL);
ops[i].jf, ops[i].k); print_hu(PRINT_ANY, "code", "%hu ", ops[i].code);
print_hhu(PRINT_ANY, "jt", "%hhu ", ops[i].jt);
print_hhu(PRINT_ANY, "jf", "%hhu ", ops[i].jf);
if (i == len - 1)
print_uint(PRINT_ANY, "k", "%u\'", ops[i].k);
else
print_uint(PRINT_ANY, "k", "%u,", ops[i].k);
close_json_object();
}
fprintf(f, "%hu %hhu %hhu %u\'", ops[i].code, ops[i].jt, close_json_array(PRINT_JSON, NULL);
ops[i].jf, ops[i].k); close_json_object();
} }
static void bpf_map_pin_report(const struct bpf_elf_map *pin, static void bpf_map_pin_report(const struct bpf_elf_map *pin,

View File

@ -152,6 +152,48 @@ static unsigned int ll_idx_a2n(const char *name)
return idx; return idx;
} }
static int ll_link_get(const char *name, int index)
{
struct {
struct nlmsghdr n;
struct ifinfomsg ifm;
char buf[1024];
} req = {
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
.n.nlmsg_flags = NLM_F_REQUEST,
.n.nlmsg_type = RTM_GETLINK,
.ifm.ifi_index = index,
};
__u32 filt_mask = RTEXT_FILTER_VF | RTEXT_FILTER_SKIP_STATS;
struct rtnl_handle rth = {};
struct nlmsghdr *answer;
int rc = 0;
if (rtnl_open(&rth, 0) < 0)
return 0;
addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
if (name)
addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name,
strlen(name) + 1);
if (rtnl_talk(&rth, &req.n, &answer) < 0)
goto out;
/* add entry to cache */
rc = ll_remember_index(answer, NULL);
if (!rc) {
struct ifinfomsg *ifm = NLMSG_DATA(answer);
rc = ifm->ifi_index;
}
free(answer);
out:
rtnl_close(&rth);
return rc;
}
const char *ll_index_to_name(unsigned int idx) const char *ll_index_to_name(unsigned int idx)
{ {
static char buf[IFNAMSIZ]; static char buf[IFNAMSIZ];
@ -164,6 +206,12 @@ const char *ll_index_to_name(unsigned int idx)
if (im) if (im)
return im->name; return im->name;
if (ll_link_get(NULL, idx) == idx) {
im = ll_get_by_index(idx);
if (im)
return im->name;
}
if (if_indextoname(idx, buf) == NULL) if (if_indextoname(idx, buf) == NULL)
snprintf(buf, IFNAMSIZ, "if%u", idx); snprintf(buf, IFNAMSIZ, "if%u", idx);
@ -204,12 +252,28 @@ unsigned ll_name_to_index(const char *name)
if (im) if (im)
return im->index; return im->index;
idx = if_nametoindex(name); idx = ll_link_get(name, 0);
if (idx == 0)
idx = if_nametoindex(name);
if (idx == 0) if (idx == 0)
idx = ll_idx_a2n(name); idx = ll_idx_a2n(name);
return idx; return idx;
} }
void ll_drop_by_index(unsigned index)
{
struct ll_cache *im;
im = ll_get_by_index(index);
if (!im)
return;
hlist_del(&im->idx_hash);
hlist_del(&im->name_hash);
free(im);
}
void ll_init_map(struct rtnl_handle *rth) void ll_init_map(struct rtnl_handle *rth)
{ {
static int initialized; static int initialized;

View File

@ -69,6 +69,8 @@ bridge \- show / manipulate bridge addresses and devices
.BR self " ] [ " master " ] [ " router " ] [ " use " ] [ " extern_learn " ] [ " sticky " ] [ " .BR self " ] [ " master " ] [ " router " ] [ " use " ] [ " extern_learn " ] [ " sticky " ] [ "
.B dst .B dst
.IR IPADDR " ] [ " .IR IPADDR " ] [ "
.B src_vni
.IR SRC_VNI " ] ["
.B vni .B vni
.IR VNI " ] [" .IR VNI " ] ["
.B port .B port
@ -473,6 +475,13 @@ is of type VXLAN.
the IP address of the destination the IP address of the destination
VXLAN tunnel endpoint where the Ethernet MAC ADDRESS resides. VXLAN tunnel endpoint where the Ethernet MAC ADDRESS resides.
.TP
.BI src_vni " SRC VNI"
the src VNI Network Identifier (or VXLAN Segment ID)
this entry belongs to. Used only when the vxlan device is in
external or collect metadata mode. If omitted the value specified at
vxlan device creation will be used.
.TP .TP
.BI vni " VNI" .BI vni " VNI"
the VXLAN VNI Network Identifier (or VXLAN Segment ID) the VXLAN VNI Network Identifier (or VXLAN Segment ID)

View File

@ -63,6 +63,22 @@ devlink-dev \- devlink device configuration
.BR "devlink dev reload" .BR "devlink dev reload"
.IR DEV .IR DEV
.ti -8
.BR "devlink dev info"
.RI "[ "
.IR DEV
.RI "]"
.ti -8
.BR "devlink dev flash"
.IR DEV
.BR file
.IR PATH
.RI "["
.BR target
.IR ID
.RI "]"
.SH "DESCRIPTION" .SH "DESCRIPTION"
.SS devlink dev show - display devlink device attributes .SS devlink dev show - display devlink device attributes
@ -151,6 +167,48 @@ If this argument is omitted all parameters supported by devlink devices are list
.I "DEV" .I "DEV"
- Specifies the devlink device to reload. - Specifies the devlink device to reload.
.SS devlink dev info - display device information.
Display device information provided by the driver. This command can be used
to query versions of the hardware components or device components which
can't be updated (
.I fixed
) as well as device firmware which can be updated. For firmware components
.I running
displays the versions of firmware currently loaded into the device, while
.I stored
reports the versions in device's flash.
.I Running
and
.I stored
versions may differ after flash has been updated, but before reboot.
.PP
.I "DEV"
- specifies the devlink device to show.
If this argument is omitted all devices are listed.
.SS devlink dev flash - write device's non-volatile memory.
.PP
.I "DEV"
- specifies the devlink device to write to.
.BR file
.I PATH
- Path to the file which will be written into device's flash. The path needs
to be relative to one of the directories searched by the kernel firmware loaded,
such as /lib/firmware.
.BR component
.I NAME
- If device stores multiple firmware images in non-volatile memory, this
parameter may be used to indicate which firmware image should be written.
The value of
.I NAME
should match the component names from
.B "devlink dev info"
and may be driver-dependent.
.SH "EXAMPLES" .SH "EXAMPLES"
.PP .PP
devlink dev show devlink dev show

197
man/man8/devlink-health.8 Normal file
View File

@ -0,0 +1,197 @@
.TH DEVLINK\-HEALTH 8 "20 Feb 2019" "iproute2" "Linux"
.SH NAME
devlink-health \- devlink health reporting and recovery
.SH SYNOPSIS
.sp
.ad l
.in +8
.ti -8
.B devlink
.RI "[ " OPTIONS " ]"
.B health
.RI " { " COMMAND " | "
.BR help " }"
.sp
.ti -8
.IR OPTIONS " := { "
\fB\-V\fR[\fIersion\fR] }
.ti -8
.BR "devlink health show"
.RI "[ " DEV ""
.B reporter
.RI ""REPORTER " ] "
.ti -8
.BR "devlink health recover"
.RI "" DEV ""
.B reporter
.RI "" REPORTER ""
.ti -8
.BR "devlink health diagnose"
.RI "" DEV ""
.B reporter
.RI "" REPORTER ""
.ti -8
.BR "devlink health dump show"
.RI "" DEV ""
.B reporter
.RI "" REPORTER ""
.ti -8
.BR "devlink health dump clear"
.RI "" DEV ""
.B reporter
.RI "" REPORTER ""
.ti -8
.BR "devlink health set"
.RI "" DEV ""
.B reporter
.RI "" REPORTER ""
.RI " { "
.B grace_period | auto_recover
.RI " } { "
.RI "" msec ""
.RI "|"
.RI "" boolean ""
.RI " } "
.ti -8
.B devlink health help
.SH "DESCRIPTION"
.SS devlink health show - Show status and configuration on all supported reporters on all devlink devices.
.PP
.I "DEV"
- specifies the devlink device.
.PP
.I "REPORTER"
- specifies the reporter's name registered on the devlink device.
.SS devlink health recover - Initiate a recovery operation on a reporter.
This action performs a recovery and increases the recoveries counter on success.
.PP
.I "DEV"
- specifies the devlink device.
.PP
.I "REPORTER"
- specifies the reporter's name registered on the devlink device.
.SS devlink health diagnose - Retrieve diagnostics data on a reporter.
.PP
.I "DEV"
- specifies the devlink device.
.PP
.I "REPORTER"
- specifies the reporter's name registered on the devlink device.
.SS devlink health dump show - Display the last saved dump.
.PD 0
.P
devlink health saves a single dump per reporter. If an dump is
.P
not already stored by the Devlink, this command will generate a new
.P
dump. The dump can be generated either automatically when a
.P
reporter reports on an error or manually at the user's request.
.PD
.PP
.I "DEV"
- specifies the devlink device.
.PP
.I "REPORTER"
- specifies the reporter's name registered on the devlink device.
.SS devlink health dump clear - Delete the saved dump.
Deleting the saved dump enables a generation of a new dump on
.PD 0
.P
the next "devlink health dump show" command.
.PD
.PP
.I "DEV"
- specifies the devlink device.
.PP
.I "REPORTER"
- specifies the reporter's name registered on the devlink device.
.SS devlink health set - Enable the user to configure:
.PD 0
1) grace_period [msec] - Time interval between consecutive auto recoveries.
.P
2) auto_recover [true/false] - Indicates whether the devlink should execute automatic recover on error.
.P
Please note that this command is not supported on a reporter which
doesn't support a recovery method.
.PD
.PP
.I "DEV"
- specifies the devlink device.
.PP
.I "REPORTER"
- specifies the reporter's name registered on the devlink device.
.SH "EXAMPLES"
.PP
devlink health show
.RS 4
List status and configuration of available reporters on devices.
.RE
.PP
devlink health recover pci/0000:00:09.0 reporter tx
.RS 4
Initiate recovery on tx reporter registered on pci/0000:00:09.0.
.RE
.PP
devlink health diagnose pci/0000:00:09.0 reporter tx
.RS 4
List diagnostics data on the specified device and reporter.
.RE
.PP
devlink health dump show pci/0000:00:09.0 reporter tx
.RS 4
Display the last saved dump on the specified device and reporter.
.RE
.PP
devlink health dump clear pci/0000:00:09.0 reporter tx
.RS 4
Delete saved dump on the specified device and reporter.
.RE
.PP
devlink health set pci/0000:00:09.0 reporter tx grace_period 3500
.RS 4
Set time interval between auto recoveries to minimum of 3500 msec on
the specified device and reporter.
.RE
.PP
devlink health set pci/0000:00:09.0 reporter tx auto_recover false
.RS 4
Turn off auto recovery on the specified device and reporter.
.RE
.SH SEE ALSO
.BR devlink (8),
.BR devlink-dev (8),
.BR devlink-port (8),
.BR devlink-param (8),
.BR devlink-region (8),
.br
.SH AUTHOR
Aya Levin <ayal@mellanox.com>

View File

@ -128,6 +128,16 @@ Behaviour of this argument it the same for every command.
- specifies the devlink device to show pools. - specifies the devlink device to show pools.
If this argument is omitted all pools of all devices are listed. If this argument is omitted all pools of all devices are listed.
Display available pools listing their
.B type, size, thtype
and
.B cell_size. cell_size
is the allocation granularity of memory within the shared buffer. Drivers
may round up, round down or reject
.B size
passed to the set command if it is not multiple of
.B cell_size.
.SS devlink sb pool set - set attributes of pool .SS devlink sb pool set - set attributes of pool
.PP .PP

View File

@ -7,7 +7,7 @@ devlink \- Devlink tool
.in +8 .in +8
.ti -8 .ti -8
.B devlink .B devlink
.RI "[ " OPTIONS " ] { " dev | port | monitor | sb | resource | region " } { " COMMAND " | " .RI "[ " OPTIONS " ] { " dev | port | monitor | sb | resource | region | health " } { " COMMAND " | "
.BR help " }" .BR help " }"
.sp .sp
@ -78,6 +78,10 @@ Turn on verbose output.
.B region .B region
- devlink address region access - devlink address region access
.TP
.B health
- devlink reporting and recovery
.SS .SS
.I COMMAND .I COMMAND
@ -109,6 +113,7 @@ Exit status is 0 if command was successful or a positive integer upon failure.
.BR devlink-sb (8), .BR devlink-sb (8),
.BR devlink-resource (8), .BR devlink-resource (8),
.BR devlink-region (8), .BR devlink-region (8),
.BR devlink-health (8),
.br .br
.SH REPORTING BUGS .SH REPORTING BUGS

View File

@ -19,6 +19,10 @@ ip-netns \- process network namespace management
.B ip netns add .B ip netns add
.I NETNSNAME .I NETNSNAME
.ti -8
.B ip netns attach
.I NETNSNAME PID
.ti -8 .ti -8
.B ip [-all] netns del .B ip [-all] netns del
.RI "[ " NETNSNAME " ]" .RI "[ " NETNSNAME " ]"
@ -89,6 +93,12 @@ This command displays all of the network namespaces in /var/run/netns
If NAME is available in /var/run/netns/ this command creates a new If NAME is available in /var/run/netns/ this command creates a new
network namespace and assigns NAME. network namespace and assigns NAME.
.TP
.B ip netns attach NAME PID - create a new named network namespace
.sp
If NAME is available in /var/run/netns/ this command attaches the network
namespace of the process PID to NAME as if it were created with ip netns.
.TP .TP
.B ip [-all] netns delete [ NAME ] - delete the name of a network namespace(s) .B ip [-all] netns delete [ NAME ] - delete the name of a network namespace(s)
.sp .sp

View File

@ -89,7 +89,7 @@ ip-xfrm \- transform configuration
.IR MASK " ] ]" .IR MASK " ] ]"
.ti -8 .ti -8
.BR "ip xfrm state" " { " deleteall " | " list " } [" .BR "ip xfrm state " deleteall " ["
.IR ID " ]" .IR ID " ]"
.RB "[ " mode .RB "[ " mode
.IR MODE " ]" .IR MODE " ]"
@ -98,6 +98,17 @@ ip-xfrm \- transform configuration
.RB "[ " flag .RB "[ " flag
.IR FLAG-LIST " ]" .IR FLAG-LIST " ]"
.ti -8
.BR "ip xfrm state " list " ["
.IR ID " ]"
.RB "[ " nokeys " ]"
.RB "[ " mode
.IR MODE " ]"
.RB "[ " reqid
.IR REQID " ]"
.RB "[ " flag
.IR FLAG-LIST " ]"
.ti -8 .ti -8
.BR "ip xfrm state flush" " [ " proto .BR "ip xfrm state flush" " [ " proto
.IR XFRM-PROTO " ]" .IR XFRM-PROTO " ]"
@ -381,6 +392,8 @@ ip-xfrm \- transform configuration
.BR "ip xfrm monitor" " [" .BR "ip xfrm monitor" " ["
.BI all-nsid .BI all-nsid
] [ ] [
.BI nokeys
] [
.BI all .BI all
| |
.IR LISTofXFRM-OBJECTS " ]" .IR LISTofXFRM-OBJECTS " ]"

View File

@ -341,16 +341,19 @@ Display SCTP sockets.
.B \-\-vsock .B \-\-vsock
Display vsock sockets (alias for -f vsock). Display vsock sockets (alias for -f vsock).
.TP .TP
.B \-\-xdp
Display XDP sockets (alias for -f xdp).
.TP
.B \-f FAMILY, \-\-family=FAMILY .B \-f FAMILY, \-\-family=FAMILY
Display sockets of type FAMILY. Display sockets of type FAMILY.
Currently the following families are supported: unix, inet, inet6, link, netlink, vsock. Currently the following families are supported: unix, inet, inet6, link, netlink, vsock, xdp.
.TP .TP
.B \-A QUERY, \-\-query=QUERY, \-\-socket=QUERY .B \-A QUERY, \-\-query=QUERY, \-\-socket=QUERY
List of socket tables to dump, separated by commas. The following identifiers List of socket tables to dump, separated by commas. The following identifiers
are understood: all, inet, tcp, udp, raw, unix, packet, netlink, unix_dgram, are understood: all, inet, tcp, udp, raw, unix, packet, netlink, unix_dgram,
unix_stream, unix_seqpacket, packet_raw, packet_dgram, dccp, sctp, unix_stream, unix_seqpacket, packet_raw, packet_dgram, dccp, sctp,
vsock_stream, vsock_dgram. Any item in the list may optionally be prefixed by vsock_stream, vsock_dgram, xdp Any item in the list may optionally be
an exclamation mark prefixed by an exclamation mark
.RB ( ! ) .RB ( ! )
to exclude that socket table from being dumped. to exclude that socket table from being dumped.
.TP .TP

168
misc/ss.c
View File

@ -42,6 +42,7 @@
#include <linux/unix_diag.h> #include <linux/unix_diag.h>
#include <linux/netdevice.h> /* for MAX_ADDR_LEN */ #include <linux/netdevice.h> /* for MAX_ADDR_LEN */
#include <linux/filter.h> #include <linux/filter.h>
#include <linux/xdp_diag.h>
#include <linux/packet_diag.h> #include <linux/packet_diag.h>
#include <linux/netlink_diag.h> #include <linux/netlink_diag.h>
#include <linux/sctp.h> #include <linux/sctp.h>
@ -209,6 +210,7 @@ enum {
VSOCK_ST_DB, VSOCK_ST_DB,
VSOCK_DG_DB, VSOCK_DG_DB,
TIPC_DB, TIPC_DB,
XDP_DB,
MAX_DB MAX_DB
}; };
@ -320,6 +322,10 @@ static const struct filter default_dbs[MAX_DB] = {
.states = TIPC_SS_CONN, .states = TIPC_SS_CONN,
.families = FAMILY_MASK(AF_TIPC), .families = FAMILY_MASK(AF_TIPC),
}, },
[XDP_DB] = {
.states = (1 << SS_CLOSE),
.families = FAMILY_MASK(AF_XDP),
},
}; };
static const struct filter default_afs[AF_MAX] = { static const struct filter default_afs[AF_MAX] = {
@ -351,6 +357,10 @@ static const struct filter default_afs[AF_MAX] = {
.dbs = (1 << TIPC_DB), .dbs = (1 << TIPC_DB),
.states = TIPC_SS_CONN, .states = TIPC_SS_CONN,
}, },
[AF_XDP] = {
.dbs = (1 << XDP_DB),
.states = (1 << SS_CLOSE),
},
}; };
static int do_default = 1; static int do_default = 1;
@ -377,7 +387,7 @@ static int filter_db_parse(struct filter *f, const char *s)
ENTRY(all, UDP_DB, DCCP_DB, TCP_DB, RAW_DB, ENTRY(all, UDP_DB, DCCP_DB, TCP_DB, RAW_DB,
UNIX_ST_DB, UNIX_DG_DB, UNIX_SQ_DB, UNIX_ST_DB, UNIX_DG_DB, UNIX_SQ_DB,
PACKET_R_DB, PACKET_DG_DB, NETLINK_DB, PACKET_R_DB, PACKET_DG_DB, NETLINK_DB,
SCTP_DB, VSOCK_ST_DB, VSOCK_DG_DB), SCTP_DB, VSOCK_ST_DB, VSOCK_DG_DB, XDP_DB),
ENTRY(inet, UDP_DB, DCCP_DB, TCP_DB, SCTP_DB, RAW_DB), ENTRY(inet, UDP_DB, DCCP_DB, TCP_DB, SCTP_DB, RAW_DB),
ENTRY(udp, UDP_DB), ENTRY(udp, UDP_DB),
ENTRY(dccp, DCCP_DB), ENTRY(dccp, DCCP_DB),
@ -402,6 +412,7 @@ static int filter_db_parse(struct filter *f, const char *s)
ENTRY(v_str, VSOCK_ST_DB), /* alias for vsock_stream */ ENTRY(v_str, VSOCK_ST_DB), /* alias for vsock_stream */
ENTRY(vsock_dgram, VSOCK_DG_DB), ENTRY(vsock_dgram, VSOCK_DG_DB),
ENTRY(v_dgr, VSOCK_DG_DB), /* alias for vsock_dgram */ ENTRY(v_dgr, VSOCK_DG_DB), /* alias for vsock_dgram */
ENTRY(xdp, XDP_DB),
#undef ENTRY #undef ENTRY
}; };
bool enable = true; bool enable = true;
@ -1352,6 +1363,9 @@ static void sock_state_print(struct sockstat *s)
case AF_VSOCK: case AF_VSOCK:
sock_name = vsock_netid_name(s->type); sock_name = vsock_netid_name(s->type);
break; break;
case AF_XDP:
sock_name = "xdp";
break;
default: default:
sock_name = "unknown"; sock_name = "unknown";
} }
@ -4095,6 +4109,142 @@ static int packet_show(struct filter *f)
return rc; return rc;
} }
static int xdp_stats_print(struct sockstat *s, const struct filter *f)
{
const char *addr, *port;
char q_str[16];
s->local.family = s->remote.family = AF_XDP;
if (f->f) {
if (run_ssfilter(f->f, s) == 0)
return 1;
}
sock_state_print(s);
if (s->iface) {
addr = xll_index_to_name(s->iface);
snprintf(q_str, sizeof(q_str), "q%d", s->lport);
port = q_str;
sock_addr_print(addr, ":", port, NULL);
} else {
sock_addr_print("", "*", "", NULL);
}
sock_addr_print("", "*", "", NULL);
proc_ctx_print(s);
if (show_details)
sock_details_print(s);
return 0;
}
static void xdp_show_ring(const char *name, struct xdp_diag_ring *ring)
{
out("\n\t%s(", name);
out("entries:%u", ring->entries);
out(")");
}
static void xdp_show_umem(struct xdp_diag_umem *umem, struct xdp_diag_ring *fr,
struct xdp_diag_ring *cr)
{
out("\n\tumem(");
out("id:%u", umem->id);
out(",size:%llu", umem->size);
out(",num_pages:%u", umem->num_pages);
out(",chunk_size:%u", umem->chunk_size);
out(",headroom:%u", umem->headroom);
out(",ifindex:%u", umem->ifindex);
out(",qid:%u", umem->queue_id);
out(",zc:%u", umem->flags & XDP_DU_F_ZEROCOPY);
out(",refs:%u", umem->refs);
out(")");
if (fr)
xdp_show_ring("fr", fr);
if (cr)
xdp_show_ring("cr", cr);
}
static int xdp_show_sock(struct nlmsghdr *nlh, void *arg)
{
struct xdp_diag_ring *rx = NULL, *tx = NULL, *fr = NULL, *cr = NULL;
struct xdp_diag_msg *msg = NLMSG_DATA(nlh);
struct rtattr *tb[XDP_DIAG_MAX + 1];
struct xdp_diag_info *info = NULL;
struct xdp_diag_umem *umem = NULL;
const struct filter *f = arg;
struct sockstat stat = {};
parse_rtattr(tb, XDP_DIAG_MAX, (struct rtattr *)(msg + 1),
nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*msg)));
stat.type = msg->xdiag_type;
stat.ino = msg->xdiag_ino;
stat.state = SS_CLOSE;
stat.sk = cookie_sk_get(&msg->xdiag_cookie[0]);
if (tb[XDP_DIAG_INFO]) {
info = RTA_DATA(tb[XDP_DIAG_INFO]);
stat.iface = info->ifindex;
stat.lport = info->queue_id;
}
if (tb[XDP_DIAG_UID])
stat.uid = rta_getattr_u32(tb[XDP_DIAG_UID]);
if (tb[XDP_DIAG_RX_RING])
rx = RTA_DATA(tb[XDP_DIAG_RX_RING]);
if (tb[XDP_DIAG_TX_RING])
tx = RTA_DATA(tb[XDP_DIAG_TX_RING]);
if (tb[XDP_DIAG_UMEM])
umem = RTA_DATA(tb[XDP_DIAG_UMEM]);
if (tb[XDP_DIAG_UMEM_FILL_RING])
fr = RTA_DATA(tb[XDP_DIAG_UMEM_FILL_RING]);
if (tb[XDP_DIAG_UMEM_COMPLETION_RING])
cr = RTA_DATA(tb[XDP_DIAG_UMEM_COMPLETION_RING]);
if (tb[XDP_DIAG_MEMINFO]) {
__u32 *skmeminfo = RTA_DATA(tb[XDP_DIAG_MEMINFO]);
stat.rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
}
if (xdp_stats_print(&stat, f))
return 0;
if (show_details) {
if (rx)
xdp_show_ring("rx", rx);
if (tx)
xdp_show_ring("tx", tx);
if (umem)
xdp_show_umem(umem, fr, cr);
}
if (show_mem)
print_skmeminfo(tb, XDP_DIAG_MEMINFO); // really?
return 0;
}
static int xdp_show(struct filter *f)
{
DIAG_REQUEST(req, struct xdp_diag_req r);
if (!filter_af_get(f, AF_XDP) || !(f->states & (1 << SS_CLOSE)))
return 0;
req.r.sdiag_family = AF_XDP;
req.r.xdiag_show = XDP_SHOW_INFO | XDP_SHOW_RING_CFG | XDP_SHOW_UMEM |
XDP_SHOW_MEMINFO;
return handle_netlink_request(f, &req.nlh, sizeof(req), xdp_show_sock);
}
static int netlink_show_one(struct filter *f, static int netlink_show_one(struct filter *f,
int prot, int pid, unsigned int groups, int prot, int pid, unsigned int groups,
int state, int dst_pid, unsigned int dst_group, int state, int dst_pid, unsigned int dst_group,
@ -4482,6 +4632,9 @@ static int generic_show_sock(struct nlmsghdr *nlh, void *arg)
case AF_VSOCK: case AF_VSOCK:
ret = vsock_show_sock(nlh, arg); ret = vsock_show_sock(nlh, arg);
break; break;
case AF_XDP:
ret = xdp_show_sock(nlh, arg);
break;
default: default:
ret = -1; ret = -1;
} }
@ -4720,7 +4873,7 @@ static void _usage(FILE *dest)
" --tipc display only TIPC sockets\n" " --tipc display only TIPC sockets\n"
" --vsock display only vsock sockets\n" " --vsock display only vsock sockets\n"
" -f, --family=FAMILY display sockets of type FAMILY\n" " -f, --family=FAMILY display sockets of type FAMILY\n"
" FAMILY := {inet|inet6|link|unix|netlink|vsock|tipc|help}\n" " FAMILY := {inet|inet6|link|unix|netlink|vsock|tipc|xdp|help}\n"
"\n" "\n"
" -K, --kill forcibly close sockets, display what was closed\n" " -K, --kill forcibly close sockets, display what was closed\n"
" -H, --no-header Suppress header line\n" " -H, --no-header Suppress header line\n"
@ -4808,6 +4961,9 @@ static int scan_state(const char *state)
#define OPT_TOS 259 #define OPT_TOS 259
/* Values of 'x' are already used so a non-character is used */
#define OPT_XDPSOCK 260
static const struct option long_opts[] = { static const struct option long_opts[] = {
{ "numeric", 0, 0, 'n' }, { "numeric", 0, 0, 'n' },
{ "resolve", 0, 0, 'r' }, { "resolve", 0, 0, 'r' },
@ -4846,6 +5002,7 @@ static const struct option long_opts[] = {
{ "tos", 0, 0, OPT_TOS }, { "tos", 0, 0, OPT_TOS },
{ "kill", 0, 0, 'K' }, { "kill", 0, 0, 'K' },
{ "no-header", 0, 0, 'H' }, { "no-header", 0, 0, 'H' },
{ "xdp", 0, 0, OPT_XDPSOCK},
{ 0 } { 0 }
}; };
@ -4933,6 +5090,9 @@ int main(int argc, char *argv[])
case '0': case '0':
filter_af_set(&current_filter, AF_PACKET); filter_af_set(&current_filter, AF_PACKET);
break; break;
case OPT_XDPSOCK:
filter_af_set(&current_filter, AF_XDP);
break;
case 'f': case 'f':
if (strcmp(optarg, "inet") == 0) if (strcmp(optarg, "inet") == 0)
filter_af_set(&current_filter, AF_INET); filter_af_set(&current_filter, AF_INET);
@ -4948,6 +5108,8 @@ int main(int argc, char *argv[])
filter_af_set(&current_filter, AF_TIPC); filter_af_set(&current_filter, AF_TIPC);
else if (strcmp(optarg, "vsock") == 0) else if (strcmp(optarg, "vsock") == 0)
filter_af_set(&current_filter, AF_VSOCK); filter_af_set(&current_filter, AF_VSOCK);
else if (strcmp(optarg, "xdp") == 0)
filter_af_set(&current_filter, AF_XDP);
else if (strcmp(optarg, "help") == 0) else if (strcmp(optarg, "help") == 0)
help(); help();
else { else {
@ -5148,6 +5310,8 @@ int main(int argc, char *argv[])
vsock_show(&current_filter); vsock_show(&current_filter);
if (current_filter.dbs & (1<<TIPC_DB)) if (current_filter.dbs & (1<<TIPC_DB))
tipc_show(&current_filter); tipc_show(&current_filter);
if (current_filter.dbs & (1<<XDP_DB))
xdp_show(&current_filter);
if (show_users || show_proc_ctx || show_sock_ctx) if (show_users || show_proc_ctx || show_sock_ctx)
user_ent_destroy(); user_ent_destroy();

View File

@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
include ../config.mk include ../config.mk
TARGETS := TARGETS :=
@ -6,7 +6,8 @@ TARGETS :=
ifeq ($(HAVE_MNL),y) ifeq ($(HAVE_MNL),y)
CFLAGS += -I./include/uapi/ CFLAGS += -I./include/uapi/
RDMA_OBJ = rdma.o utils.o dev.o link.o res.o 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
TARGETS += rdma TARGETS += rdma
endif endif

View File

@ -1,11 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* /*
* dev.c RDMA tool * dev.c RDMA tool
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Leon Romanovsky <leonro@mellanox.com> * Authors: Leon Romanovsky <leonro@mellanox.com>
*/ */

View File

@ -5,8 +5,7 @@
#include <linux/types.h> #include <linux/types.h>
enum { enum {
RDMA_NL_RDMA_CM = 1, RDMA_NL_IWCM = 2,
RDMA_NL_IWCM,
RDMA_NL_RSVD, RDMA_NL_RSVD,
RDMA_NL_LS, /* RDMA Local Services */ RDMA_NL_LS, /* RDMA Local Services */
RDMA_NL_NLDEV, /* RDMA device interface */ RDMA_NL_NLDEV, /* RDMA device interface */
@ -14,8 +13,7 @@ enum {
}; };
enum { enum {
RDMA_NL_GROUP_CM = 1, RDMA_NL_GROUP_IWPM = 2,
RDMA_NL_GROUP_IWPM,
RDMA_NL_GROUP_LS, RDMA_NL_GROUP_LS,
RDMA_NL_NUM_GROUPS RDMA_NL_NUM_GROUPS
}; };
@ -24,15 +22,17 @@ enum {
#define RDMA_NL_GET_OP(type) (type & ((1 << 10) - 1)) #define RDMA_NL_GET_OP(type) (type & ((1 << 10) - 1))
#define RDMA_NL_GET_TYPE(client, op) ((client << 10) + op) #define RDMA_NL_GET_TYPE(client, op) ((client << 10) + op)
enum { /* The minimum version that the iwpm kernel supports */
RDMA_NL_RDMA_CM_ID_STATS = 0, #define IWPM_UABI_VERSION_MIN 3
RDMA_NL_RDMA_CM_NUM_OPS
};
/* The latest version that the iwpm kernel supports */
#define IWPM_UABI_VERSION 4
/* iwarp port mapper message flags */
enum { enum {
RDMA_NL_RDMA_CM_ATTR_SRC_ADDR = 1,
RDMA_NL_RDMA_CM_ATTR_DST_ADDR, /* Do not map the port for this IWPM request */
RDMA_NL_RDMA_CM_NUM_ATTR, IWPM_FLAGS_NO_PORT_MAP = (1 << 0),
}; };
/* iwarp port mapper op-codes */ /* iwarp port mapper op-codes */
@ -45,6 +45,7 @@ enum {
RDMA_NL_IWPM_HANDLE_ERR, RDMA_NL_IWPM_HANDLE_ERR,
RDMA_NL_IWPM_MAPINFO, RDMA_NL_IWPM_MAPINFO,
RDMA_NL_IWPM_MAPINFO_NUM, RDMA_NL_IWPM_MAPINFO_NUM,
RDMA_NL_IWPM_HELLO,
RDMA_NL_IWPM_NUM_OPS RDMA_NL_IWPM_NUM_OPS
}; };
@ -83,20 +84,38 @@ enum {
IWPM_NLA_MANAGE_MAPPING_UNSPEC = 0, IWPM_NLA_MANAGE_MAPPING_UNSPEC = 0,
IWPM_NLA_MANAGE_MAPPING_SEQ, IWPM_NLA_MANAGE_MAPPING_SEQ,
IWPM_NLA_MANAGE_ADDR, IWPM_NLA_MANAGE_ADDR,
IWPM_NLA_MANAGE_MAPPED_LOC_ADDR, IWPM_NLA_MANAGE_FLAGS,
IWPM_NLA_MANAGE_MAPPING_MAX
};
enum {
IWPM_NLA_RMANAGE_MAPPING_UNSPEC = 0,
IWPM_NLA_RMANAGE_MAPPING_SEQ,
IWPM_NLA_RMANAGE_ADDR,
IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR,
/* The following maintains bisectability of rdma-core */
IWPM_NLA_MANAGE_MAPPED_LOC_ADDR = IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR,
IWPM_NLA_RMANAGE_MAPPING_ERR, IWPM_NLA_RMANAGE_MAPPING_ERR,
IWPM_NLA_RMANAGE_MAPPING_MAX IWPM_NLA_RMANAGE_MAPPING_MAX
}; };
#define IWPM_NLA_MANAGE_MAPPING_MAX 3
#define IWPM_NLA_QUERY_MAPPING_MAX 4
#define IWPM_NLA_MAPINFO_SEND_MAX 3 #define IWPM_NLA_MAPINFO_SEND_MAX 3
#define IWPM_NLA_REMOVE_MAPPING_MAX 3
enum { enum {
IWPM_NLA_QUERY_MAPPING_UNSPEC = 0, IWPM_NLA_QUERY_MAPPING_UNSPEC = 0,
IWPM_NLA_QUERY_MAPPING_SEQ, IWPM_NLA_QUERY_MAPPING_SEQ,
IWPM_NLA_QUERY_LOCAL_ADDR, IWPM_NLA_QUERY_LOCAL_ADDR,
IWPM_NLA_QUERY_REMOTE_ADDR, IWPM_NLA_QUERY_REMOTE_ADDR,
IWPM_NLA_QUERY_FLAGS,
IWPM_NLA_QUERY_MAPPING_MAX,
};
enum {
IWPM_NLA_RQUERY_MAPPING_UNSPEC = 0,
IWPM_NLA_RQUERY_MAPPING_SEQ,
IWPM_NLA_RQUERY_LOCAL_ADDR,
IWPM_NLA_RQUERY_REMOTE_ADDR,
IWPM_NLA_RQUERY_MAPPED_LOC_ADDR, IWPM_NLA_RQUERY_MAPPED_LOC_ADDR,
IWPM_NLA_RQUERY_MAPPED_REM_ADDR, IWPM_NLA_RQUERY_MAPPED_REM_ADDR,
IWPM_NLA_RQUERY_MAPPING_ERR, IWPM_NLA_RQUERY_MAPPING_ERR,
@ -114,6 +133,7 @@ enum {
IWPM_NLA_MAPINFO_UNSPEC = 0, IWPM_NLA_MAPINFO_UNSPEC = 0,
IWPM_NLA_MAPINFO_LOCAL_ADDR, IWPM_NLA_MAPINFO_LOCAL_ADDR,
IWPM_NLA_MAPINFO_MAPPED_ADDR, IWPM_NLA_MAPINFO_MAPPED_ADDR,
IWPM_NLA_MAPINFO_FLAGS,
IWPM_NLA_MAPINFO_MAX IWPM_NLA_MAPINFO_MAX
}; };
@ -132,6 +152,12 @@ enum {
IWPM_NLA_ERR_MAX IWPM_NLA_ERR_MAX
}; };
enum {
IWPM_NLA_HELLO_UNSPEC = 0,
IWPM_NLA_HELLO_ABI_VERSION,
IWPM_NLA_HELLO_MAX
};
/* /*
* Local service operations: * Local service operations:
* RESOLVE - The client requests the local service to resolve a path. * RESOLVE - The client requests the local service to resolve a path.
@ -430,6 +456,16 @@ enum rdma_nldev_attr {
RDMA_NLDEV_ATTR_DRIVER_S64, /* s64 */ RDMA_NLDEV_ATTR_DRIVER_S64, /* s64 */
RDMA_NLDEV_ATTR_DRIVER_U64, /* u64 */ RDMA_NLDEV_ATTR_DRIVER_U64, /* u64 */
/*
* Indexes to get/set secific entry,
* for QP use RDMA_NLDEV_ATTR_RES_LQPN
*/
RDMA_NLDEV_ATTR_RES_PDN, /* u32 */
RDMA_NLDEV_ATTR_RES_CQN, /* u32 */
RDMA_NLDEV_ATTR_RES_MRN, /* u32 */
RDMA_NLDEV_ATTR_RES_CM_IDN, /* u32 */
RDMA_NLDEV_ATTR_RES_CTXN, /* u32 */
/* /*
* Always the end * Always the end
*/ */

View File

@ -1,11 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* /*
* link.c RDMA tool * link.c RDMA tool
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Leon Romanovsky <leonro@mellanox.com> * Authors: Leon Romanovsky <leonro@mellanox.com>
*/ */

View File

@ -1,11 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* /*
* rdma.c RDMA tool * rdma.c RDMA tool
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Leon Romanovsky <leonro@mellanox.com> * Authors: Leon Romanovsky <leonro@mellanox.com>
*/ */

View File

@ -1,11 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* /*
* rdma.c RDMA tool * rdma.c RDMA tool
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Leon Romanovsky <leonro@mellanox.com> * Authors: Leon Romanovsky <leonro@mellanox.com>
*/ */
#ifndef _RDMA_TOOL_H_ #ifndef _RDMA_TOOL_H_
@ -35,13 +30,20 @@
#define MAX_NUMBER_OF_FILTERS 64 #define MAX_NUMBER_OF_FILTERS 64
struct filters { struct filters {
const char *name; const char *name;
bool is_number; uint8_t is_number:1;
uint8_t is_doit:1;
}; };
struct filter_entry { struct filter_entry {
struct list_head list; struct list_head list;
char *key; char *key;
char *value; char *value;
/*
* This field menas that we can try to issue .doit calback
* on value above. This value can be converted to integer
* with simple atoi(). Otherwise "is_doit" will be false.
*/
uint8_t is_doit:1;
}; };
struct dev_map { struct dev_map {
@ -106,10 +108,12 @@ struct dev_map *dev_map_lookup(struct rd *rd, bool allow_port_index);
/* /*
* Filter manipulation * Filter manipulation
*/ */
bool rd_doit_index(struct rd *rd, uint32_t *idx);
int rd_build_filter(struct rd *rd, const struct filters valid_filters[]); int rd_build_filter(struct rd *rd, const struct filters valid_filters[]);
bool rd_check_is_filtered(struct rd *rd, const char *key, uint32_t val); bool rd_is_filtered_attr(struct rd *rd, const char *key, uint32_t val,
bool rd_check_is_string_filtered(struct rd *rd, const char *key, const char *val); struct nlattr *attr);
bool rd_check_is_key_exist(struct rd *rd, const char *key); bool rd_is_string_filtered_attr(struct rd *rd, const char *key, const char *val,
struct nlattr *attr);
/* /*
* Netlink * Netlink
*/ */

275
rdma/res-cmid.c Normal file
View File

@ -0,0 +1,275 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* res-cmid.c RDMA tool
* Authors: Leon Romanovsky <leonro@mellanox.com>
*/
#include "res.h"
#include <inttypes.h>
static void print_qp_type(struct rd *rd, uint32_t val)
{
if (rd->json_output)
jsonw_string_field(rd->jw, "qp-type", qp_types_to_str(val));
else
pr_out("qp-type %s ", qp_types_to_str(val));
}
static const char *cm_id_state_to_str(uint8_t idx)
{
static const char *const cm_id_states_str[] = {
"IDLE", "ADDR_QUERY", "ADDR_RESOLVED",
"ROUTE_QUERY", "ROUTE_RESOLVED", "CONNECT",
"DISCONNECT", "ADDR_BOUND", "LISTEN",
"DEVICE_REMOVAL", "DESTROYING"
};
if (idx < ARRAY_SIZE(cm_id_states_str))
return cm_id_states_str[idx];
return "UNKNOWN";
}
static const char *cm_id_ps_to_str(uint32_t ps)
{
switch (ps) {
case RDMA_PS_IPOIB:
return "IPoIB";
case RDMA_PS_IB:
return "IPoIB";
case RDMA_PS_TCP:
return "TCP";
case RDMA_PS_UDP:
return "UDP";
default:
return "---";
}
}
static void print_cm_id_state(struct rd *rd, uint8_t state)
{
if (rd->json_output) {
jsonw_string_field(rd->jw, "state", cm_id_state_to_str(state));
return;
}
pr_out("state %s ", cm_id_state_to_str(state));
}
static void print_ps(struct rd *rd, uint32_t ps)
{
if (rd->json_output) {
jsonw_string_field(rd->jw, "ps", cm_id_ps_to_str(ps));
return;
}
pr_out("ps %s ", cm_id_ps_to_str(ps));
}
static void print_ipaddr(struct rd *rd, const char *key, char *addrstr,
uint16_t port)
{
if (rd->json_output) {
int name_size = INET6_ADDRSTRLEN + strlen(":65535");
char json_name[name_size];
snprintf(json_name, name_size, "%s:%u", addrstr, port);
jsonw_string_field(rd->jw, key, json_name);
return;
}
pr_out("%s %s:%u ", key, addrstr, port);
}
static int ss_ntop(struct nlattr *nla_line, char *addr_str, uint16_t *port)
{
struct __kernel_sockaddr_storage *addr;
addr = (struct __kernel_sockaddr_storage *)mnl_attr_get_payload(
nla_line);
switch (addr->ss_family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
if (!inet_ntop(AF_INET, (const void *)&sin->sin_addr, addr_str,
INET6_ADDRSTRLEN))
return -EINVAL;
*port = ntohs(sin->sin_port);
break;
}
case AF_INET6: {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
if (!inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
addr_str, INET6_ADDRSTRLEN))
return -EINVAL;
*port = ntohs(sin6->sin6_port);
break;
}
default:
return -EINVAL;
}
return 0;
}
static int res_cm_id_line(struct rd *rd, const char *name, int idx,
struct nlattr **nla_line)
{
char src_addr_str[INET6_ADDRSTRLEN];
char dst_addr_str[INET6_ADDRSTRLEN];
uint16_t src_port, dst_port;
uint32_t port = 0, pid = 0;
uint8_t type = 0, state;
uint32_t lqpn = 0, ps;
uint32_t cm_idn = 0;
char *comm = NULL;
if (!nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
!nla_line[RDMA_NLDEV_ATTR_RES_PS] ||
(!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
!nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
return MNL_CB_ERROR;
}
if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
port = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
if (port && port != rd->port_idx)
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_LQPN])
lqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
if (rd_is_filtered_attr(rd, "lqpn", lqpn,
nla_line[RDMA_NLDEV_ATTR_RES_LQPN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
type = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
if (rd_is_string_filtered_attr(rd, "qp-type", qp_types_to_str(type),
nla_line[RDMA_NLDEV_ATTR_RES_TYPE]))
goto out;
ps = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PS]);
if (rd_is_string_filtered_attr(rd, "ps", cm_id_ps_to_str(ps),
nla_line[RDMA_NLDEV_ATTR_RES_PS]))
goto out;
state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
if (rd_is_string_filtered_attr(rd, "state", cm_id_state_to_str(state),
nla_line[RDMA_NLDEV_ATTR_RES_STATE]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR])
if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR],
src_addr_str, &src_port))
goto out;
if (rd_is_string_filtered_attr(rd, "src-addr", src_addr_str,
nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR]))
goto out;
if (rd_is_filtered_attr(rd, "src-port", src_port,
nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR])
if (ss_ntop(nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR],
dst_addr_str, &dst_port))
goto out;
if (rd_is_string_filtered_attr(rd, "dst-addr", dst_addr_str,
nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR]))
goto out;
if (rd_is_filtered_attr(rd, "dst-port", dst_port,
nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR]))
goto out;
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]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_CM_IDN])
cm_idn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CM_IDN]);
if (rd_is_filtered_attr(rd, "cm-idn", cm_idn,
nla_line[RDMA_NLDEV_ATTR_RES_CM_IDN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) {
/* discard const from mnl_attr_get_str */
comm = (char *)mnl_attr_get_str(
nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
}
if (rd->json_output)
jsonw_start_array(rd->jw);
print_link(rd, idx, name, port, nla_line);
res_print_uint(rd, "cm-idn", cm_idn,
nla_line[RDMA_NLDEV_ATTR_RES_CM_IDN]);
res_print_uint(rd, "lqpn", lqpn, nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
if (nla_line[RDMA_NLDEV_ATTR_RES_TYPE])
print_qp_type(rd, type);
print_cm_id_state(rd, state);
print_ps(rd, ps);
res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
print_comm(rd, comm, nla_line);
if (nla_line[RDMA_NLDEV_ATTR_RES_SRC_ADDR])
print_ipaddr(rd, "src-addr", src_addr_str, src_port);
if (nla_line[RDMA_NLDEV_ATTR_RES_DST_ADDR])
print_ipaddr(rd, "dst-addr", dst_addr_str, dst_port);
print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
newline(rd);
out: if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
free(comm);
return MNL_CB_OK;
}
int res_cm_id_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
struct rd *rd = data;
const char *name;
int idx;
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;
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
return res_cm_id_line(rd, name, idx, tb);
}
int res_cm_id_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;
int ret = MNL_CB_OK;
const char *name;
int idx;
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_RES_CM_ID])
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_RES_CM_ID];
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_cm_id_line(rd, name, idx, nla_line);
if (ret != MNL_CB_OK)
break;
}
return ret;
}

160
rdma/res-cq.c Normal file
View File

@ -0,0 +1,160 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* res-cq.c RDMA tool
* Authors: Leon Romanovsky <leonro@mellanox.com>
*/
#include "res.h"
#include <inttypes.h>
static const char *poll_ctx_to_str(uint8_t idx)
{
static const char * const cm_id_states_str[] = {
"DIRECT", "SOFTIRQ", "WORKQUEUE", "UNBOUND_WORKQUEUE"};
if (idx < ARRAY_SIZE(cm_id_states_str))
return cm_id_states_str[idx];
return "UNKNOWN";
}
static void print_poll_ctx(struct rd *rd, uint8_t poll_ctx, struct nlattr *attr)
{
if (!attr)
return;
if (rd->json_output) {
jsonw_string_field(rd->jw, "poll-ctx",
poll_ctx_to_str(poll_ctx));
return;
}
pr_out("poll-ctx %s ", poll_ctx_to_str(poll_ctx));
}
static int res_cq_line(struct rd *rd, const char *name, int idx,
struct nlattr **nla_line)
{
char *comm = NULL;
uint32_t pid = 0;
uint8_t poll_ctx = 0;
uint32_t ctxn = 0;
uint32_t cqn = 0;
uint64_t users;
uint32_t cqe;
if (!nla_line[RDMA_NLDEV_ATTR_RES_CQE] ||
!nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
(!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
!nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
return MNL_CB_ERROR;
}
cqe = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CQE]);
users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
if (rd_is_filtered_attr(rd, "users", users,
nla_line[RDMA_NLDEV_ATTR_RES_USECNT]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX])
poll_ctx =
mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]);
if (rd_is_string_filtered_attr(rd, "poll-ctx",
poll_ctx_to_str(poll_ctx),
nla_line[RDMA_NLDEV_ATTR_RES_POLL_CTX]))
goto out;
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]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_CQN])
cqn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CQN]);
if (rd_is_filtered_attr(rd, "cqn", cqn,
nla_line[RDMA_NLDEV_ATTR_RES_CQN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_CTXN])
ctxn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CTXN]);
if (rd_is_filtered_attr(rd, "ctxn", ctxn,
nla_line[RDMA_NLDEV_ATTR_RES_CTXN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
/* discard const from mnl_attr_get_str */
comm = (char *)mnl_attr_get_str(
nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
if (rd->json_output)
jsonw_start_array(rd->jw);
print_dev(rd, idx, name);
res_print_uint(rd, "cqn", cqn, nla_line[RDMA_NLDEV_ATTR_RES_CQN]);
res_print_uint(rd, "cqe", cqe, nla_line[RDMA_NLDEV_ATTR_RES_CQE]);
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]);
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);
print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
newline(rd);
out: if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
free(comm);
return MNL_CB_OK;
}
int res_cq_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
struct rd *rd = data;
const char *name;
uint32_t idx;
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;
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
return res_cq_line(rd, name, idx, tb);
}
int res_cq_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;
int ret = MNL_CB_OK;
const char *name;
uint32_t idx;
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_RES_CQ])
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_RES_CQ];
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_cq_line(rd, name, idx, nla_line);
if (ret != MNL_CB_OK)
break;
}
return ret;
}

133
rdma/res-mr.c Normal file
View File

@ -0,0 +1,133 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* res-mr.c RDMA tool
* Authors: Leon Romanovsky <leonro@mellanox.com>
*/
#include "res.h"
#include <inttypes.h>
static int res_mr_line(struct rd *rd, const char *name, int idx,
struct nlattr **nla_line)
{
uint32_t rkey = 0, lkey = 0;
uint64_t iova = 0, mrlen;
char *comm = NULL;
uint32_t pdn = 0;
uint32_t mrn = 0;
uint32_t pid = 0;
if (!nla_line[RDMA_NLDEV_ATTR_RES_MRLEN] ||
(!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
!nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
return MNL_CB_ERROR;
}
if (nla_line[RDMA_NLDEV_ATTR_RES_RKEY])
rkey = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RKEY]);
if (nla_line[RDMA_NLDEV_ATTR_RES_LKEY])
lkey = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LKEY]);
if (nla_line[RDMA_NLDEV_ATTR_RES_IOVA])
iova = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_IOVA]);
mrlen = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]);
if (rd_is_filtered_attr(rd, "mrlen", mrlen,
nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]))
goto out;
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]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_MRN])
mrn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_MRN]);
if (rd_is_filtered_attr(rd, "mrn", mrn,
nla_line[RDMA_NLDEV_ATTR_RES_MRN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_PDN])
pdn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
if (rd_is_filtered_attr(rd, "pdn", pdn,
nla_line[RDMA_NLDEV_ATTR_RES_PDN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
/* discard const from mnl_attr_get_str */
comm = (char *)mnl_attr_get_str(
nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
if (rd->json_output)
jsonw_start_array(rd->jw);
print_dev(rd, idx, name);
res_print_uint(rd, "mrn", mrn, nla_line[RDMA_NLDEV_ATTR_RES_MRN]);
print_key(rd, "rkey", rkey, nla_line[RDMA_NLDEV_ATTR_RES_RKEY]);
print_key(rd, "lkey", lkey, nla_line[RDMA_NLDEV_ATTR_RES_LKEY]);
print_key(rd, "iova", iova, nla_line[RDMA_NLDEV_ATTR_RES_IOVA]);
res_print_uint(rd, "mrlen", mrlen, nla_line[RDMA_NLDEV_ATTR_RES_MRLEN]);
res_print_uint(rd, "pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
print_comm(rd, comm, nla_line);
print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
newline(rd);
out:
if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
free(comm);
return MNL_CB_OK;
}
int res_mr_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
struct rd *rd = data;
const char *name;
uint32_t idx;
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;
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
return res_mr_line(rd, name, idx, tb);
}
int res_mr_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;
int ret = MNL_CB_OK;
const char *name;
uint32_t idx;
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_RES_MR])
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_RES_MR];
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_mr_line(rd, name, idx, nla_line);
if (ret != MNL_CB_OK)
break;
}
return ret;
}

136
rdma/res-pd.c Normal file
View File

@ -0,0 +1,136 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* res-pd.c RDMA tool
* Authors: Leon Romanovsky <leonro@mellanox.com>
*/
#include "res.h"
#include <inttypes.h>
static int res_pd_line(struct rd *rd, const char *name, int idx,
struct nlattr **nla_line)
{
uint32_t local_dma_lkey = 0, unsafe_global_rkey = 0;
char *comm = NULL;
uint32_t ctxn = 0;
uint32_t pid = 0;
uint32_t pdn = 0;
uint64_t users;
if (!nla_line[RDMA_NLDEV_ATTR_RES_USECNT] ||
(!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
!nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
return MNL_CB_ERROR;
}
if (nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY])
local_dma_lkey = mnl_attr_get_u32(
nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]);
users = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
if (rd_is_filtered_attr(rd, "users", users,
nla_line[RDMA_NLDEV_ATTR_RES_USECNT]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY])
unsafe_global_rkey = mnl_attr_get_u32(
nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]);
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]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_CTXN])
ctxn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_CTXN]);
if (rd_is_filtered_attr(rd, "ctxn", ctxn,
nla_line[RDMA_NLDEV_ATTR_RES_CTXN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_PDN])
pdn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
if (rd_is_filtered_attr(rd, "pdn", pdn,
nla_line[RDMA_NLDEV_ATTR_RES_PDN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
/* discard const from mnl_attr_get_str */
comm = (char *)mnl_attr_get_str(
nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
if (rd->json_output)
jsonw_start_array(rd->jw);
print_dev(rd, idx, name);
res_print_uint(rd, "pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
print_key(rd, "local_dma_lkey", local_dma_lkey,
nla_line[RDMA_NLDEV_ATTR_RES_LOCAL_DMA_LKEY]);
res_print_uint(rd, "users", users,
nla_line[RDMA_NLDEV_ATTR_RES_USECNT]);
print_key(rd, "unsafe_global_rkey", unsafe_global_rkey,
nla_line[RDMA_NLDEV_ATTR_RES_UNSAFE_GLOBAL_RKEY]);
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);
print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
newline(rd);
out: if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
free(comm);
return MNL_CB_OK;
}
int res_pd_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
struct rd *rd = data;
const char *name;
uint32_t idx;
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;
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
return res_pd_line(rd, name, idx, tb);
}
int res_pd_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;
int ret = MNL_CB_OK;
const char *name;
uint32_t idx;
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_RES_PD])
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_RES_PD];
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_pd_line(rd, name, idx, nla_line);
if (ret != MNL_CB_OK)
break;
}
return ret;
}

240
rdma/res-qp.c Normal file
View File

@ -0,0 +1,240 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
* res-qp.c RDMA tool
* Authors: Leon Romanovsky <leonro@mellanox.com>
*/
#include "res.h"
#include <inttypes.h>
static const char *path_mig_to_str(uint8_t idx)
{
static const char *const path_mig_str[] = { "MIGRATED", "REARM",
"ARMED" };
if (idx < ARRAY_SIZE(path_mig_str))
return path_mig_str[idx];
return "UNKNOWN";
}
static const char *qp_states_to_str(uint8_t idx)
{
static const char *const qp_states_str[] = { "RESET", "INIT", "RTR",
"RTS", "SQD", "SQE",
"ERR" };
if (idx < ARRAY_SIZE(qp_states_str))
return qp_states_str[idx];
return "UNKNOWN";
}
static void print_rqpn(struct rd *rd, uint32_t val, struct nlattr **nla_line)
{
if (!nla_line[RDMA_NLDEV_ATTR_RES_RQPN])
return;
if (rd->json_output)
jsonw_uint_field(rd->jw, "rqpn", val);
else
pr_out("rqpn %u ", val);
}
static void print_type(struct rd *rd, uint32_t val)
{
if (rd->json_output)
jsonw_string_field(rd->jw, "type", qp_types_to_str(val));
else
pr_out("type %s ", qp_types_to_str(val));
}
static void print_state(struct rd *rd, uint32_t val)
{
if (rd->json_output)
jsonw_string_field(rd->jw, "state", qp_states_to_str(val));
else
pr_out("state %s ", qp_states_to_str(val));
}
static void print_rqpsn(struct rd *rd, uint32_t val, struct nlattr **nla_line)
{
if (!nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN])
return;
if (rd->json_output)
jsonw_uint_field(rd->jw, "rq-psn", val);
else
pr_out("rq-psn %u ", val);
}
static void print_pathmig(struct rd *rd, uint32_t val, struct nlattr **nla_line)
{
if (!nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE])
return;
if (rd->json_output)
jsonw_string_field(rd->jw, "path-mig-state",
path_mig_to_str(val));
else
pr_out("path-mig-state %s ", path_mig_to_str(val));
}
static int res_qp_line(struct rd *rd, const char *name, int idx,
struct nlattr **nla_line)
{
uint32_t lqpn, rqpn = 0, rq_psn = 0, sq_psn;
uint8_t type, state, path_mig_state = 0;
uint32_t port = 0, pid = 0;
uint32_t pdn = 0;
char *comm = NULL;
if (!nla_line[RDMA_NLDEV_ATTR_RES_LQPN] ||
!nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN] ||
!nla_line[RDMA_NLDEV_ATTR_RES_TYPE] ||
!nla_line[RDMA_NLDEV_ATTR_RES_STATE] ||
(!nla_line[RDMA_NLDEV_ATTR_RES_PID] &&
!nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) {
return MNL_CB_ERROR;
}
if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX])
port = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]);
if (port != rd->port_idx)
goto out;
lqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
if (rd_is_filtered_attr(rd, "lqpn", lqpn,
nla_line[RDMA_NLDEV_ATTR_RES_LQPN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_PDN])
pdn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
if (rd_is_filtered_attr(rd, "pdn", pdn,
nla_line[RDMA_NLDEV_ATTR_RES_PDN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_RQPN])
rqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQPN]);
if (rd_is_filtered_attr(rd, "rqpn", rqpn,
nla_line[RDMA_NLDEV_ATTR_RES_RQPN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN])
rq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]);
if (rd_is_filtered_attr(rd, "rq-psn", rq_psn,
nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]))
goto out;
sq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN]);
if (rd_is_filtered_attr(rd, "sq-psn", sq_psn,
nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE])
path_mig_state = mnl_attr_get_u8(
nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]);
if (rd_is_string_filtered_attr(
rd, "path-mig-state", path_mig_to_str(path_mig_state),
nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]))
goto out;
type = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_TYPE]);
if (rd_is_string_filtered_attr(rd, "type", qp_types_to_str(type),
nla_line[RDMA_NLDEV_ATTR_RES_TYPE]))
goto out;
state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]);
if (rd_is_string_filtered_attr(rd, "state", qp_states_to_str(state),
nla_line[RDMA_NLDEV_ATTR_RES_STATE]))
goto out;
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]))
goto out;
if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])
/* discard const from mnl_attr_get_str */
comm = (char *)mnl_attr_get_str(
nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]);
if (rd->json_output)
jsonw_start_array(rd->jw);
print_link(rd, idx, name, port, nla_line);
res_print_uint(rd, "lqpn", lqpn, nla_line[RDMA_NLDEV_ATTR_RES_LQPN]);
print_rqpn(rd, rqpn, nla_line);
print_type(rd, type);
print_state(rd, state);
print_rqpsn(rd, rq_psn, nla_line);
res_print_uint(rd, "sq-psn", sq_psn,
nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN]);
print_pathmig(rd, path_mig_state, nla_line);
res_print_uint(rd, "pdn", pdn, nla_line[RDMA_NLDEV_ATTR_RES_PDN]);
res_print_uint(rd, "pid", pid, nla_line[RDMA_NLDEV_ATTR_RES_PID]);
print_comm(rd, comm, nla_line);
print_driver_table(rd, nla_line[RDMA_NLDEV_ATTR_DRIVER]);
newline(rd);
out:
if (nla_line[RDMA_NLDEV_ATTR_RES_PID])
free(comm);
return MNL_CB_OK;
}
int res_qp_idx_parse_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {};
struct rd *rd = data;
const char *name;
uint32_t idx;
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;
name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]);
idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
return res_qp_line(rd, name, idx, tb);
}
int res_qp_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;
int ret = MNL_CB_OK;
const char *name;
uint32_t idx;
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_RES_QP])
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_RES_QP];
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_qp_line(rd, name, idx, nla_line);
if (ret != MNL_CB_OK)
break;
}
return ret;
}

File diff suppressed because it is too large Load Diff

148
rdma/res.h Normal file
View File

@ -0,0 +1,148 @@
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/*
* res.h RDMA tool
* Authors: Leon Romanovsky <leonro@mellanox.com>
*/
#ifndef _RDMA_TOOL_RES_H_
#define _RDMA_TOOL_RES_H_
#include "rdma.h"
int _res_send_msg(struct rd *rd, uint32_t command, mnl_cb_t callback);
int _res_send_idx_msg(struct rd *rd, uint32_t command, mnl_cb_t callback,
uint32_t idx, uint32_t id);
int res_pd_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_pd_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_mr_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_mr_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_cq_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_cq_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_cm_id_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_cm_id_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_qp_parse_cb(const struct nlmsghdr *nlh, void *data);
int res_qp_idx_parse_cb(const struct nlmsghdr *nlh, void *data);
#define RES_FUNC(name, command, valid_filters, strict_port, id) \
static inline int _##name(struct rd *rd) \
{ \
uint32_t idx; \
int ret; \
if (id) { \
ret = rd_doit_index(rd, &idx); \
if (ret) { \
ret = _res_send_idx_msg(rd, command, \
name##_idx_parse_cb, \
idx, id); \
if (!ret) \
return ret; \
/* Fallback for old systems without .doit callbacks */ \
} \
} \
return _res_send_msg(rd, command, name##_parse_cb); \
} \
static inline int name(struct rd *rd) \
{ \
int ret = rd_build_filter(rd, valid_filters); \
if (ret) \
return ret; \
if ((uintptr_t)valid_filters != (uintptr_t)NULL) { \
ret = rd_set_arg_to_devname(rd); \
if (ret) \
return ret; \
} \
if (strict_port) \
return rd_exec_dev(rd, _##name); \
else \
return rd_exec_link(rd, _##name, strict_port); \
}
static const
struct filters pd_valid_filters[MAX_NUMBER_OF_FILTERS] = {
{ .name = "dev", .is_number = false },
{ .name = "users", .is_number = true },
{ .name = "pid", .is_number = true },
{ .name = "ctxn", .is_number = true },
{ .name = "pdn", .is_number = true, .is_doit = true },
{ .name = "ctxn", .is_number = true }
};
RES_FUNC(res_pd, RDMA_NLDEV_CMD_RES_PD_GET, pd_valid_filters, true,
RDMA_NLDEV_ATTR_RES_PDN);
static const
struct filters mr_valid_filters[MAX_NUMBER_OF_FILTERS] = {
{ .name = "dev", .is_number = false },
{ .name = "rkey", .is_number = true },
{ .name = "lkey", .is_number = true },
{ .name = "mrlen", .is_number = true },
{ .name = "pid", .is_number = true },
{ .name = "mrn", .is_number = true, .is_doit = true },
{ .name = "pdn", .is_number = true }
};
RES_FUNC(res_mr, RDMA_NLDEV_CMD_RES_MR_GET, mr_valid_filters, true,
RDMA_NLDEV_ATTR_RES_MRN);
static const
struct filters cq_valid_filters[MAX_NUMBER_OF_FILTERS] = {
{ .name = "dev", .is_number = false },
{ .name = "users", .is_number = true },
{ .name = "poll-ctx", .is_number = false },
{ .name = "pid", .is_number = true },
{ .name = "cqn", .is_number = true, .is_doit = true },
{ .name = "ctxn", .is_number = true }
};
RES_FUNC(res_cq, RDMA_NLDEV_CMD_RES_CQ_GET, cq_valid_filters, true,
RDMA_NLDEV_ATTR_RES_CQN);
static const
struct filters cm_id_valid_filters[MAX_NUMBER_OF_FILTERS] = {
{ .name = "link", .is_number = false },
{ .name = "lqpn", .is_number = true },
{ .name = "qp-type", .is_number = false },
{ .name = "state", .is_number = false },
{ .name = "ps", .is_number = false },
{ .name = "dev-type", .is_number = false },
{ .name = "transport-type", .is_number = false },
{ .name = "pid", .is_number = true },
{ .name = "src-addr", .is_number = false },
{ .name = "src-port", .is_number = true },
{ .name = "dst-addr", .is_number = false },
{ .name = "dst-port", .is_number = true },
{ .name = "cm-idn", .is_number = true, .is_doit = true }
};
RES_FUNC(res_cm_id, RDMA_NLDEV_CMD_RES_CM_ID_GET, cm_id_valid_filters, false,
RDMA_NLDEV_ATTR_RES_CM_IDN);
static const struct
filters qp_valid_filters[MAX_NUMBER_OF_FILTERS] = {
{ .name = "link", .is_number = false },
{ .name = "lqpn", .is_number = true, .is_doit = true },
{ .name = "rqpn", .is_number = true },
{ .name = "pid", .is_number = true },
{ .name = "sq-psn", .is_number = true },
{ .name = "rq-psn", .is_number = true },
{ .name = "type", .is_number = false },
{ .name = "path-mig-state", .is_number = false },
{ .name = "state", .is_number = false },
{ .name = "pdn", .is_number = true },
};
RES_FUNC(res_qp, RDMA_NLDEV_CMD_RES_QP_GET, qp_valid_filters, false,
RDMA_NLDEV_ATTR_RES_LQPN);
char *get_task_name(uint32_t pid);
void print_dev(struct rd *rd, uint32_t idx, const char *name);
void print_link(struct rd *rd, uint32_t idx, const char *name, uint32_t port,
struct nlattr **nla_line);
void print_key(struct rd *rd, const char *name, uint64_t val,
struct nlattr *nlattr);
void res_print_uint(struct rd *rd, const char *name, uint64_t val,
struct nlattr *nlattr);
void print_comm(struct rd *rd, const char *str, struct nlattr **nla_line);
const char *qp_types_to_str(uint8_t idx);
#endif /* _RDMA_TOOL_RES_H_ */

View File

@ -1,11 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* /*
* utils.c RDMA tool * utils.c RDMA tool
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Leon Romanovsky <leonro@mellanox.com> * Authors: Leon Romanovsky <leonro@mellanox.com>
*/ */
@ -126,6 +121,7 @@ static int add_filter(struct rd *rd, char *key, char *value,
struct filter_entry *fe; struct filter_entry *fe;
bool key_found = false; bool key_found = false;
int idx = 0; int idx = 0;
char *endp;
int ret; int ret;
fe = calloc(1, sizeof(*fe)); fe = calloc(1, sizeof(*fe));
@ -168,6 +164,11 @@ static int add_filter(struct rd *rd, char *key, char *value,
goto err_alloc; goto err_alloc;
} }
errno = 0;
strtol(fe->value, &endp, 10);
if (valid_filters[idx].is_doit && !errno && *endp == '\0')
fe->is_doit = true;
for (idx = 0; idx < strlen(fe->value); idx++) for (idx = 0; idx < strlen(fe->value); idx++)
fe->value[idx] = tolower(fe->value[idx]); fe->value[idx] = tolower(fe->value[idx]);
@ -182,6 +183,20 @@ err:
return ret; return ret;
} }
bool rd_doit_index(struct rd *rd, uint32_t *idx)
{
struct filter_entry *fe;
list_for_each_entry(fe, &rd->filter_list, list) {
if (fe->is_doit) {
*idx = atoi(fe->value);
return true;
}
}
return false;
}
int rd_build_filter(struct rd *rd, const struct filters valid_filters[]) int rd_build_filter(struct rd *rd, const struct filters valid_filters[])
{ {
int ret = 0; int ret = 0;
@ -218,7 +233,7 @@ out:
return ret; return ret;
} }
bool rd_check_is_key_exist(struct rd *rd, const char *key) static bool rd_check_is_key_exist(struct rd *rd, const char *key)
{ {
struct filter_entry *fe; struct filter_entry *fe;
@ -234,8 +249,8 @@ bool rd_check_is_key_exist(struct rd *rd, const char *key)
* Check if string entry is filtered: * Check if string entry is filtered:
* * key doesn't exist -> user didn't request -> not filtered * * key doesn't exist -> user didn't request -> not filtered
*/ */
bool rd_check_is_string_filtered(struct rd *rd, static bool rd_check_is_string_filtered(struct rd *rd, const char *key,
const char *key, const char *val) const char *val)
{ {
bool key_is_filtered = false; bool key_is_filtered = false;
struct filter_entry *fe; struct filter_entry *fe;
@ -285,7 +300,7 @@ out:
* Check if key is filtered: * Check if key is filtered:
* key doesn't exist -> user didn't request -> not filtered * key doesn't exist -> user didn't request -> not filtered
*/ */
bool rd_check_is_filtered(struct rd *rd, const char *key, uint32_t val) static bool rd_check_is_filtered(struct rd *rd, const char *key, uint32_t val)
{ {
bool key_is_filtered = false; bool key_is_filtered = false;
struct filter_entry *fe; struct filter_entry *fe;
@ -334,6 +349,24 @@ out:
return key_is_filtered; return key_is_filtered;
} }
bool rd_is_filtered_attr(struct rd *rd, const char *key, uint32_t val,
struct nlattr *attr)
{
if (!attr)
return rd_check_is_key_exist(rd, key);
return rd_check_is_filtered(rd, key, val);
}
bool rd_is_string_filtered_attr(struct rd *rd, const char *key, const char *val,
struct nlattr *attr)
{
if (!attr)
rd_check_is_key_exist(rd, key);
return rd_check_is_string_filtered(rd, key, val);
}
static void filters_cleanup(struct rd *rd) static void filters_cleanup(struct rd *rd)
{ {
struct filter_entry *fe, *tmp; struct filter_entry *fe, *tmp;
@ -796,27 +829,37 @@ static int print_driver_entry(struct rd *rd, struct nlattr *key_attr,
struct nlattr *val_attr, struct nlattr *val_attr,
enum rdma_nldev_print_type print_type) enum rdma_nldev_print_type print_type)
{ {
const char *key_str = mnl_attr_get_str(key_attr);
int attr_type = nla_type(val_attr); int attr_type = nla_type(val_attr);
int ret = -EINVAL;
char *key_str;
if (asprintf(&key_str, "drv_%s", mnl_attr_get_str(key_attr)) == -1)
return -ENOMEM;
switch (attr_type) { switch (attr_type) {
case RDMA_NLDEV_ATTR_DRIVER_STRING: case RDMA_NLDEV_ATTR_DRIVER_STRING:
return print_driver_string(rd, key_str, ret = print_driver_string(rd, key_str,
mnl_attr_get_str(val_attr)); mnl_attr_get_str(val_attr));
break;
case RDMA_NLDEV_ATTR_DRIVER_S32: case RDMA_NLDEV_ATTR_DRIVER_S32:
return print_driver_s32(rd, key_str, ret = print_driver_s32(rd, key_str, mnl_attr_get_u32(val_attr),
mnl_attr_get_u32(val_attr), print_type); print_type);
break;
case RDMA_NLDEV_ATTR_DRIVER_U32: case RDMA_NLDEV_ATTR_DRIVER_U32:
return print_driver_u32(rd, key_str, ret = print_driver_u32(rd, key_str, mnl_attr_get_u32(val_attr),
mnl_attr_get_u32(val_attr), print_type); print_type);
break;
case RDMA_NLDEV_ATTR_DRIVER_S64: case RDMA_NLDEV_ATTR_DRIVER_S64:
return print_driver_s64(rd, key_str, ret = print_driver_s64(rd, key_str, mnl_attr_get_u64(val_attr),
mnl_attr_get_u64(val_attr), print_type); print_type);
break;
case RDMA_NLDEV_ATTR_DRIVER_U64: case RDMA_NLDEV_ATTR_DRIVER_U64:
return print_driver_u64(rd, key_str, ret = print_driver_u64(rd, key_str, mnl_attr_get_u64(val_attr),
mnl_attr_get_u64(val_attr), print_type); print_type);
break;
} }
return -EINVAL; free(key_str);
return ret;
} }
void print_driver_table(struct rd *rd, struct nlattr *tb) void print_driver_table(struct rd *rd, struct nlattr *tb)

View File

@ -235,7 +235,7 @@ static int bpf_print_opt(struct filter_util *qu, FILE *f,
} }
if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN]) if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN])
bpf_print_ops(f, tb[TCA_BPF_OPS], bpf_print_ops(tb[TCA_BPF_OPS],
rta_getattr_u16(tb[TCA_BPF_OPS_LEN])); rta_getattr_u16(tb[TCA_BPF_OPS_LEN]));
if (tb[TCA_BPF_ID]) if (tb[TCA_BPF_ID])

View File

@ -114,6 +114,7 @@ static int matchall_print_opt(struct filter_util *qu, FILE *f,
struct rtattr *opt, __u32 handle) struct rtattr *opt, __u32 handle)
{ {
struct rtattr *tb[TCA_MATCHALL_MAX+1]; struct rtattr *tb[TCA_MATCHALL_MAX+1];
struct tc_matchall_pcnt *pf = NULL;
if (opt == NULL) if (opt == NULL)
return 0; return 0;
@ -143,6 +144,19 @@ static int matchall_print_opt(struct filter_util *qu, FILE *f,
print_bool(PRINT_ANY, "not_in_hw", "\n not_in_hw", true); print_bool(PRINT_ANY, "not_in_hw", "\n not_in_hw", true);
} }
if (tb[TCA_MATCHALL_PCNT]) {
if (RTA_PAYLOAD(tb[TCA_MATCHALL_PCNT]) < sizeof(*pf)) {
print_string(PRINT_FP, NULL, "Broken perf counters\n", NULL);
return -1;
}
pf = RTA_DATA(tb[TCA_MATCHALL_PCNT]);
}
if (show_stats && NULL != pf)
print_u64(PRINT_ANY, "rule_hit", " (rule hit %llu)",
(unsigned long long) pf->rhit);
if (tb[TCA_MATCHALL_ACT]) if (tb[TCA_MATCHALL_ACT])
tc_print_action(f, tb[TCA_MATCHALL_ACT], 0); tc_print_action(f, tb[TCA_MATCHALL_ACT], 0);

View File

@ -363,7 +363,7 @@ tc_print_action(FILE *f, const struct rtattr *arg, unsigned short tot_acts)
parse_rtattr_nested(tb, tot_acts, arg); parse_rtattr_nested(tb, tot_acts, arg);
if (tab_flush && NULL != tb[0] && NULL == tb[1]) if (tab_flush && tb[0] && !tb[1])
return tc_print_action_flush(f, tb[0]); return tc_print_action_flush(f, tb[0]);
open_json_array(PRINT_JSON, "actions"); open_json_array(PRINT_JSON, "actions");

View File

@ -157,7 +157,7 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg)
{ {
struct rtattr *tb[TCA_ACT_BPF_MAX + 1]; struct rtattr *tb[TCA_ACT_BPF_MAX + 1];
struct tc_act_bpf *parm; struct tc_act_bpf *parm;
int dump_ok = 0; int d_ok = 0;
if (arg == NULL) if (arg == NULL)
return -1; return -1;
@ -170,31 +170,33 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg)
} }
parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]); parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);
fprintf(f, "bpf "); print_string(PRINT_ANY, "kind", "%s ", "bpf");
if (tb[TCA_ACT_BPF_NAME]) if (tb[TCA_ACT_BPF_NAME])
fprintf(f, "%s ", rta_getattr_str(tb[TCA_ACT_BPF_NAME])); print_string(PRINT_ANY, "bpf_name", "%s ",
rta_getattr_str(tb[TCA_ACT_BPF_NAME]));
if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) { if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) {
bpf_print_ops(f, tb[TCA_ACT_BPF_OPS], bpf_print_ops(tb[TCA_ACT_BPF_OPS],
rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN])); rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN]));
fprintf(f, " "); print_string(PRINT_FP, NULL, "%s", " ");
} }
if (tb[TCA_ACT_BPF_ID]) if (tb[TCA_ACT_BPF_ID])
dump_ok = bpf_dump_prog_info(f, rta_getattr_u32(tb[TCA_ACT_BPF_ID])); d_ok = bpf_dump_prog_info(f,
if (!dump_ok && tb[TCA_ACT_BPF_TAG]) { rta_getattr_u32(tb[TCA_ACT_BPF_ID]));
if (!d_ok && tb[TCA_ACT_BPF_TAG]) {
SPRINT_BUF(b); SPRINT_BUF(b);
fprintf(f, "tag %s ", print_string(PRINT_ANY, "tag", "tag %s ",
hexstring_n2a(RTA_DATA(tb[TCA_ACT_BPF_TAG]), hexstring_n2a(RTA_DATA(tb[TCA_ACT_BPF_TAG]),
RTA_PAYLOAD(tb[TCA_ACT_BPF_TAG]), RTA_PAYLOAD(tb[TCA_ACT_BPF_TAG]),
b, sizeof(b))); b, sizeof(b)));
} }
print_action_control(f, "default-action ", parm->action, "\n"); print_action_control(f, "default-action ", parm->action, _SL_);
fprintf(f, "\tindex %u ref %d bind %d", parm->index, parm->refcnt, print_uint(PRINT_ANY, "index", "\t index %u", parm->index);
parm->bindcnt); print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt);
print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt);
if (show_stats) { if (show_stats) {
if (tb[TCA_ACT_BPF_TM]) { if (tb[TCA_ACT_BPF_TM]) {

View File

@ -199,10 +199,11 @@ print_csum(struct action_util *au, FILE *f, struct rtattr *arg)
uflag_1 = "?empty"; uflag_1 = "?empty";
} }
print_string(PRINT_ANY, "kind", "%s ", "csum");
snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s", snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
uflag_1, uflag_2, uflag_3, uflag_1, uflag_2, uflag_3,
uflag_4, uflag_5, uflag_6, uflag_7); uflag_4, uflag_5, uflag_6, uflag_7);
print_string(PRINT_ANY, "csum", "csum (%s) ", buf); print_string(PRINT_ANY, "csum", "(%s) ", buf);
print_action_control(f, "action ", sel->action, "\n"); print_action_control(f, "action ", sel->action, "\n");
print_uint(PRINT_ANY, "index", "\tindex %u", sel->index); print_uint(PRINT_ANY, "index", "\tindex %u", sel->index);

View File

@ -299,9 +299,8 @@ static int parse_ipt(struct action_util *a, int *argc_p,
int i; int i;
for (i = 0; i < rargc; i++) { for (i = 0; i < rargc; i++) {
if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { if (!argv[i] || strcmp(argv[i], "action") == 0)
break; break;
}
} }
iargc = argc = i; iargc = argc = i;
} }

View File

@ -224,9 +224,8 @@ static int parse_ipt(struct action_util *a, int *argc_p,
int i; int i;
for (i = 0; i < rargc; i++) { for (i = 0; i < rargc; i++) {
if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) { if (!argv[i] || strcmp(argv[i], "action") == 0)
break; break;
}
} }
iargc = argc = i; iargc = argc = i;
} }

View File

@ -859,7 +859,7 @@ void print_tcstats_attr(FILE *fp, struct rtattr *tb[], char *prefix, struct rtat
if (tb[TCA_STATS2]) { if (tb[TCA_STATS2]) {
print_tcstats2_attr(fp, tb[TCA_STATS2], prefix, xstats); print_tcstats2_attr(fp, tb[TCA_STATS2], prefix, xstats);
if (xstats && NULL == *xstats) if (xstats && !*xstats)
goto compat_xstats; goto compat_xstats;
return; return;
} }