diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..901467bd --- /dev/null +++ b/.clang-format @@ -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 +... diff --git a/bridge/fdb.c b/bridge/fdb.c index c4bf4039..941ce2d5 100644 --- a/bridge/fdb.c +++ b/bridge/fdb.c @@ -39,6 +39,7 @@ static void usage(void) " [ self ] [ master ] [ use ] [ router ] [ extern_learn ]\n" " [ sticky ] [ local | static | dynamic ] [ dst IPADDR ]\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"); exit(-1); } @@ -383,6 +384,7 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv) inet_prefix dst; unsigned long port = 0; unsigned long vni = ~0; + unsigned long src_vni = ~0; unsigned int via = 0; char *endptr; short vid = -1; @@ -416,6 +418,12 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv) if ((endptr && *endptr) || (vni >> 24) || vni == ULONG_MAX) 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) { NEXT_ARG(); 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) addattr32(&req.n, sizeof(req), NDA_VNI, vni); + if (src_vni != ~0) + addattr32(&req.n, sizeof(req), NDA_SRC_VNI, src_vni); if (via) addattr32(&req.n, sizeof(req), NDA_IFINDEX, via); diff --git a/devlink/devlink.c b/devlink/devlink.c index cced8d61..dc6e73fe 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "SNAPSHOT.h" #include "list.h" @@ -39,6 +41,11 @@ #define PARAM_CMODE_RUNTIME_STR "runtime" #define PARAM_CMODE_DRIVERINIT_STR "driverinit" #define PARAM_CMODE_PERMANENT_STR "permanent" +#define DL_ARGS_REQUIRED_MAX_ERR_LEN 80 + +#define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy" +#define HEALTH_REPORTER_STATE_ERROR_STR "error" +#define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80 static int g_new_line_count; @@ -199,6 +206,11 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_REGION_SNAPSHOT_ID BIT(22) #define DL_OPT_REGION_ADDRESS BIT(23) #define DL_OPT_REGION_LENGTH BIT(24) +#define DL_OPT_FLASH_FILE_NAME BIT(25) +#define DL_OPT_FLASH_COMPONENT BIT(26) +#define DL_OPT_HEALTH_REPORTER_NAME BIT(27) +#define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD BIT(27) +#define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER BIT(28) struct dl_opts { uint32_t present; /* flags of present items */ @@ -230,6 +242,11 @@ struct dl_opts { uint32_t region_snapshot_id; uint64_t region_address; uint64_t region_length; + const char *flash_file_name; + const char *flash_component; + const char *reporter_name; + uint64_t reporter_graceful_period; + bool reporter_auto_recover; }; struct dl { @@ -383,6 +400,20 @@ static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_REGION_CHUNK_DATA] = MNL_TYPE_BINARY, [DEVLINK_ATTR_REGION_CHUNK_ADDR] = MNL_TYPE_U64, [DEVLINK_ATTR_REGION_CHUNK_LEN] = MNL_TYPE_U64, + [DEVLINK_ATTR_INFO_DRIVER_NAME] = MNL_TYPE_STRING, + [DEVLINK_ATTR_INFO_SERIAL_NUMBER] = MNL_TYPE_STRING, + [DEVLINK_ATTR_INFO_VERSION_FIXED] = MNL_TYPE_NESTED, + [DEVLINK_ATTR_INFO_VERSION_RUNNING] = MNL_TYPE_NESTED, + [DEVLINK_ATTR_INFO_VERSION_STORED] = MNL_TYPE_NESTED, + [DEVLINK_ATTR_INFO_VERSION_NAME] = MNL_TYPE_STRING, + [DEVLINK_ATTR_INFO_VERSION_VALUE] = MNL_TYPE_STRING, + [DEVLINK_ATTR_HEALTH_REPORTER] = MNL_TYPE_NESTED, + [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = MNL_TYPE_STRING, + [DEVLINK_ATTR_HEALTH_REPORTER_STATE] = MNL_TYPE_U8, + [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] = MNL_TYPE_U64, + [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] = MNL_TYPE_U64, + [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS] = MNL_TYPE_U64, + [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = MNL_TYPE_U64, }; static int attr_cb(const struct nlattr *attr, void *data) @@ -814,6 +845,24 @@ static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val) return 0; } +static int dl_argv_bool(struct dl *dl, bool *p_val) +{ + char *str = dl_argv_next(dl); + int err; + + if (!str) { + pr_err("Boolean argument expected\n"); + return -EINVAL; + } + + err = strtobool(str, p_val); + if (err) { + pr_err("\"%s\" is not a valid boolean value\n", str); + return err; + } + return 0; +} + static int dl_argv_str(struct dl *dl, const char **p_str) { const char *str = dl_argv_next(dl); @@ -943,6 +992,50 @@ static int param_cmode_get(const char *cmodestr, return 0; } +struct dl_args_metadata { + uint32_t o_flag; + char err_msg[DL_ARGS_REQUIRED_MAX_ERR_LEN]; +}; + +static const struct dl_args_metadata dl_args_required[] = { + {DL_OPT_PORT_TYPE, "Port type not set."}, + {DL_OPT_PORT_COUNT, "Port split count option expected."}, + {DL_OPT_SB_POOL, "Pool index option expected."}, + {DL_OPT_SB_SIZE, "Pool size option expected."}, + {DL_OPT_SB_TYPE, "Pool type option expected."}, + {DL_OPT_SB_THTYPE, "Pool threshold type option expected."}, + {DL_OPT_SB_TH, "Threshold option expected."}, + {DL_OPT_SB_TC, "TC index option expected."}, + {DL_OPT_ESWITCH_MODE, "E-Switch mode option expected."}, + {DL_OPT_ESWITCH_INLINE_MODE, "E-Switch inline-mode option expected."}, + {DL_OPT_DPIPE_TABLE_NAME, "Dpipe table name expected."}, + {DL_OPT_DPIPE_TABLE_COUNTERS, "Dpipe table counter state expected."}, + {DL_OPT_ESWITCH_ENCAP_MODE, "E-Switch encapsulation option expected."}, + {DL_OPT_PARAM_NAME, "Parameter name expected."}, + {DL_OPT_PARAM_VALUE, "Value to set expected."}, + {DL_OPT_PARAM_CMODE, "Configuration mode expected."}, + {DL_OPT_REGION_SNAPSHOT_ID, "Region snapshot id expected."}, + {DL_OPT_REGION_ADDRESS, "Region address value expected."}, + {DL_OPT_REGION_LENGTH, "Region length value expected."}, + {DL_OPT_HEALTH_REPORTER_NAME, "Reporter's name is expected."}, +}; + +static int dl_args_finding_required_validate(uint32_t o_required, + uint32_t o_found) +{ + uint32_t o_flag; + int i; + + for (i = 0; i < ARRAY_SIZE(dl_args_required); i++) { + o_flag = dl_args_required[i].o_flag; + if ((o_required & o_flag) && !(o_found & o_flag)) { + pr_err("%s\n", dl_args_required[i].err_msg); + return -EINVAL; + } + } + return 0; +} + static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_optional) { @@ -1178,6 +1271,42 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_REGION_LENGTH; + } else if (dl_argv_match(dl, "file") && + (o_all & DL_OPT_FLASH_FILE_NAME)) { + dl_arg_inc(dl); + err = dl_argv_str(dl, &opts->flash_file_name); + if (err) + return err; + o_found |= DL_OPT_FLASH_FILE_NAME; + } else if (dl_argv_match(dl, "component") && + (o_all & DL_OPT_FLASH_COMPONENT)) { + dl_arg_inc(dl); + err = dl_argv_str(dl, &opts->flash_component); + if (err) + return err; + o_found |= DL_OPT_FLASH_COMPONENT; + } else if (dl_argv_match(dl, "reporter") && + (o_all & DL_OPT_HEALTH_REPORTER_NAME)) { + dl_arg_inc(dl); + err = dl_argv_str(dl, &opts->reporter_name); + if (err) + return err; + o_found |= DL_OPT_HEALTH_REPORTER_NAME; + } else if (dl_argv_match(dl, "grace_period") && + (o_all & DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD)) { + dl_arg_inc(dl); + err = dl_argv_uint64_t(dl, + &opts->reporter_graceful_period); + if (err) + return err; + o_found |= DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD; + } else if (dl_argv_match(dl, "auto_recover") && + (o_all & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER)) { + dl_arg_inc(dl); + err = dl_argv_bool(dl, &opts->reporter_auto_recover); + if (err) + return err; + o_found |= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -1191,114 +1320,7 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, opts->present |= DL_OPT_SB; } - if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { - pr_err("Port type option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_PORT_COUNT) && - !(o_found & DL_OPT_PORT_COUNT)) { - pr_err("Port split count option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) { - pr_err("Pool index option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) { - pr_err("Pool size option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) { - pr_err("Pool type option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) { - pr_err("Pool threshold type option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) { - pr_err("Threshold option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) { - pr_err("TC index option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_ESWITCH_MODE) && - !(o_found & DL_OPT_ESWITCH_MODE)) { - pr_err("E-Switch mode option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_ESWITCH_INLINE_MODE) && - !(o_found & DL_OPT_ESWITCH_INLINE_MODE)) { - pr_err("E-Switch inline-mode option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_DPIPE_TABLE_NAME) && - !(o_found & DL_OPT_DPIPE_TABLE_NAME)) { - pr_err("Dpipe table name expected\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_DPIPE_TABLE_COUNTERS) && - !(o_found & DL_OPT_DPIPE_TABLE_COUNTERS)) { - pr_err("Dpipe table counter state expected\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_ESWITCH_ENCAP_MODE) && - !(o_found & DL_OPT_ESWITCH_ENCAP_MODE)) { - pr_err("E-Switch encapsulation option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_PARAM_NAME) && - !(o_found & DL_OPT_PARAM_NAME)) { - pr_err("Parameter name expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_PARAM_VALUE) && - !(o_found & DL_OPT_PARAM_VALUE)) { - pr_err("Value to set expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_PARAM_CMODE) && - !(o_found & DL_OPT_PARAM_CMODE)) { - pr_err("Configuration mode expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_REGION_SNAPSHOT_ID) && - !(o_found & DL_OPT_REGION_SNAPSHOT_ID)) { - pr_err("Region snapshot id expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_REGION_ADDRESS) && - !(o_found & DL_OPT_REGION_ADDRESS)) { - pr_err("Region address value expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_REGION_LENGTH) && - !(o_found & DL_OPT_REGION_LENGTH)) { - pr_err("Region length value expected.\n"); - return -EINVAL; - } - - return 0; + return dl_args_finding_required_validate(o_required, o_found); } static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) @@ -1382,6 +1404,23 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_REGION_LENGTH) mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN, opts->region_length); + if (opts->present & DL_OPT_FLASH_FILE_NAME) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME, + opts->flash_file_name); + if (opts->present & DL_OPT_FLASH_COMPONENT) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, + opts->flash_component); + if (opts->present & DL_OPT_HEALTH_REPORTER_NAME) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME, + opts->reporter_name); + if (opts->present & DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD) + mnl_attr_put_u64(nlh, + DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD, + opts->reporter_graceful_period); + if (opts->present & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER, + opts->reporter_auto_recover); + } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -1443,6 +1482,8 @@ static void cmd_dev_help(void) pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n"); pr_err(" devlink dev param show [DEV name PARAMETER]\n"); pr_err(" devlink dev reload DEV\n"); + pr_err(" devlink dev info [ DEV ]\n"); + pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n"); } static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name, @@ -1658,10 +1699,10 @@ static void pr_out_str(struct dl *dl, const char *name, const char *val) static void pr_out_bool(struct dl *dl, const char *name, bool val) { - if (val) - pr_out_str(dl, name, "true"); + if (dl->json_output) + jsonw_bool_field(dl->jw, name, val); else - pr_out_str(dl, name, "false"); + pr_out_str(dl, name, val ? "true" : "false"); } static void pr_out_uint(struct dl *dl, const char *name, unsigned int val) @@ -1681,7 +1722,79 @@ static void pr_out_u64(struct dl *dl, const char *name, uint64_t val) if (val == (uint64_t) -1) return pr_out_str(dl, name, "unlimited"); - return pr_out_uint(dl, name, val); + if (dl->json_output) { + jsonw_u64_field(dl->jw, name, val); + } else { + if (g_indent_newline) + pr_out("%s %lu", name, val); + else + pr_out(" %s %lu", name, val); + } +} + +static void pr_out_bool_value(struct dl *dl, bool value) +{ + if (dl->json_output) + jsonw_bool(dl->jw, value); + else + pr_out(" %s", value ? "true" : "false"); +} + +static void pr_out_uint_value(struct dl *dl, unsigned int value) +{ + if (dl->json_output) + jsonw_uint(dl->jw, value); + else + pr_out(" %u", value); +} + +static void pr_out_uint64_value(struct dl *dl, uint64_t value) +{ + if (dl->json_output) + jsonw_u64(dl->jw, value); + else + pr_out(" %lu", value); +} + +static void pr_out_binary_value(struct dl *dl, uint8_t *data, uint32_t len) +{ + int i = 1; + + if (dl->json_output) + jsonw_start_array(dl->jw); + else + pr_out("\n"); + + while (i < len) { + if (dl->json_output) { + jsonw_printf(dl->jw, "%d", data[i]); + } else { + pr_out(" %02x", data[i]); + if (!(i % 16)) + pr_out("\n"); + } + i++; + } + if (dl->json_output) + jsonw_end_array(dl->jw); + else if ((i - 1) % 16) + pr_out("\n"); +} + +static void pr_out_str_value(struct dl *dl, const char *value) +{ + if (dl->json_output) + jsonw_string(dl->jw, value); + else + pr_out(" %s", value); +} + +static void pr_out_name(struct dl *dl, const char *name) +{ + if (dl->json_output) + jsonw_name(dl->jw, name); + else + pr_out(" %s:", name); } static void pr_out_region_chunk_start(struct dl *dl, uint64_t addr) @@ -1775,6 +1888,30 @@ static void pr_out_array_end(struct dl *dl) } } +static void pr_out_object_start(struct dl *dl, const char *name) +{ + if (dl->json_output) { + jsonw_name(dl->jw, name); + jsonw_start_object(dl->jw); + } else { + __pr_out_indent_inc(); + __pr_out_newline(); + pr_out("%s:", name); + __pr_out_indent_inc(); + __pr_out_newline(); + } +} + +static void pr_out_object_end(struct dl *dl) +{ + if (dl->json_output) { + jsonw_end_object(dl->jw); + } else { + __pr_out_indent_dec(); + __pr_out_indent_dec(); + } +} + static void pr_out_entry_start(struct dl *dl) { if (dl->json_output) @@ -2415,6 +2552,168 @@ static int cmd_dev_reload(struct dl *dl) return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); } +static void pr_out_versions_single(struct dl *dl, const struct nlmsghdr *nlh, + const char *name, int type) +{ + struct nlattr *version; + + mnl_attr_for_each(version, nlh, sizeof(struct genlmsghdr)) { + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + const char *ver_value; + const char *ver_name; + int err; + + if (mnl_attr_get_type(version) != type) + continue; + + err = mnl_attr_parse_nested(version, attr_cb, tb); + if (err != MNL_CB_OK) + continue; + + if (!tb[DEVLINK_ATTR_INFO_VERSION_NAME] || + !tb[DEVLINK_ATTR_INFO_VERSION_VALUE]) + continue; + + if (name) { + pr_out_object_start(dl, name); + name = NULL; + } + + ver_name = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_NAME]); + ver_value = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_VALUE]); + + pr_out_str(dl, ver_name, ver_value); + if (!dl->json_output) + __pr_out_newline(); + } + + if (!name) + pr_out_object_end(dl); +} + +static void pr_out_info(struct dl *dl, const struct nlmsghdr *nlh, + struct nlattr **tb, bool has_versions) +{ + __pr_out_handle_start(dl, tb, true, false); + + __pr_out_indent_inc(); + if (tb[DEVLINK_ATTR_INFO_DRIVER_NAME]) { + struct nlattr *nla_drv = tb[DEVLINK_ATTR_INFO_DRIVER_NAME]; + + if (!dl->json_output) + __pr_out_newline(); + pr_out_str(dl, "driver", mnl_attr_get_str(nla_drv)); + } + + if (tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER]) { + struct nlattr *nla_sn = tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER]; + + if (!dl->json_output) + __pr_out_newline(); + pr_out_str(dl, "serial_number", mnl_attr_get_str(nla_sn)); + } + __pr_out_indent_dec(); + + if (has_versions) { + pr_out_object_start(dl, "versions"); + + pr_out_versions_single(dl, nlh, "fixed", + DEVLINK_ATTR_INFO_VERSION_FIXED); + pr_out_versions_single(dl, nlh, "running", + DEVLINK_ATTR_INFO_VERSION_RUNNING); + pr_out_versions_single(dl, nlh, "stored", + DEVLINK_ATTR_INFO_VERSION_STORED); + + pr_out_object_end(dl); + } + + pr_out_handle_end(dl); +} + +static int cmd_versions_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + bool has_versions, has_info; + struct dl *dl = data; + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) + return MNL_CB_ERROR; + + has_versions = tb[DEVLINK_ATTR_INFO_VERSION_FIXED] || + tb[DEVLINK_ATTR_INFO_VERSION_RUNNING] || + tb[DEVLINK_ATTR_INFO_VERSION_STORED]; + has_info = tb[DEVLINK_ATTR_INFO_DRIVER_NAME] || + tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER] || + has_versions; + + if (has_info) + pr_out_info(dl, nlh, tb, has_versions); + + return MNL_CB_OK; +} + +static void cmd_dev_info_help(void) +{ + pr_err("Usage: devlink dev info [ DEV ]\n"); +} + +static int cmd_dev_info(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argv_match(dl, "help")) { + cmd_dev_info_help(); + return 0; + } + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_INFO_GET, flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0); + if (err) + return err; + } + + pr_out_section_start(dl, "info"); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_versions_show_cb, dl); + pr_out_section_end(dl); + return err; +} + +static void cmd_dev_flash_help(void) +{ + pr_err("Usage: devlink dev flash DEV file PATH [ component NAME ]\n"); +} + +static int cmd_dev_flash(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { + cmd_dev_flash_help(); + return 0; + } + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_FLASH_UPDATE, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_FLASH_FILE_NAME, + DL_OPT_FLASH_COMPONENT); + if (err) + return err; + + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + static int cmd_dev(struct dl *dl) { if (dl_argv_match(dl, "help")) { @@ -2433,6 +2732,12 @@ static int cmd_dev(struct dl *dl) } else if (dl_argv_match(dl, "param")) { dl_arg_inc(dl); return cmd_dev_param(dl); + } else if (dl_argv_match(dl, "info")) { + dl_arg_inc(dl); + return cmd_dev_info(dl); + } else if (dl_argv_match(dl, "flash")) { + dl_arg_inc(dl); + return cmd_dev_flash(dl); } pr_err("Command \"%s\" not found\n", dl_argv(dl)); return -ENOENT; @@ -2722,6 +3027,9 @@ static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb) mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE])); pr_out_str(dl, "thtype", threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); + if (tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE]) + pr_out_uint(dl, "cell_size", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE])); pr_out_handle_end(dl); } @@ -5553,11 +5861,427 @@ static int cmd_region(struct dl *dl) return -ENOENT; } +static int cmd_health_set_params(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_SET, + NLM_F_REQUEST | NLM_F_ACK); + err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, + DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD | + DL_OPT_HEALTH_REPORTER_AUTO_RECOVER); + if (err) + return err; + + dl_opts_put(nlh, dl); + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int cmd_health_dump_clear(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, + DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0); + if (err) + return err; + + dl_opts_put(nlh, dl); + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data) +{ + uint8_t *data; + uint32_t len; + + switch (type) { + case MNL_TYPE_FLAG: + pr_out_bool_value(dl, mnl_attr_get_u8(nl_data)); + break; + case MNL_TYPE_U8: + pr_out_uint_value(dl, mnl_attr_get_u8(nl_data)); + break; + case MNL_TYPE_U16: + pr_out_uint_value(dl, mnl_attr_get_u16(nl_data)); + break; + case MNL_TYPE_U32: + pr_out_uint_value(dl, mnl_attr_get_u32(nl_data)); + break; + case MNL_TYPE_U64: + pr_out_uint64_value(dl, mnl_attr_get_u64(nl_data)); + break; + case MNL_TYPE_NUL_STRING: + pr_out_str_value(dl, mnl_attr_get_str(nl_data)); + break; + case MNL_TYPE_BINARY: + len = mnl_attr_get_payload_len(nl_data); + data = mnl_attr_get_payload(nl_data); + pr_out_binary_value(dl, data, len); + break; + default: + return -EINVAL; + } + return MNL_CB_OK; +} + +struct nest_qentry { + int attr_type; + TAILQ_ENTRY(nest_qentry) nest_entries; +}; + +struct fmsg_cb_data { + struct dl *dl; + uint8_t value_type; + TAILQ_HEAD(, nest_qentry) qhead; +}; + +static int cmd_fmsg_nest_queue(struct fmsg_cb_data *fmsg_data, + uint8_t *attr_value, bool insert) +{ + struct nest_qentry *entry = NULL; + + if (insert) { + entry = malloc(sizeof(struct nest_qentry)); + if (!entry) + return -ENOMEM; + + entry->attr_type = *attr_value; + TAILQ_INSERT_HEAD(&fmsg_data->qhead, entry, nest_entries); + } else { + if (TAILQ_EMPTY(&fmsg_data->qhead)) + return MNL_CB_ERROR; + entry = TAILQ_FIRST(&fmsg_data->qhead); + *attr_value = entry->attr_type; + TAILQ_REMOVE(&fmsg_data->qhead, entry, nest_entries); + free(entry); + } + return MNL_CB_OK; +} + +static int cmd_fmsg_nest(struct fmsg_cb_data *fmsg_data, uint8_t nest_value, + bool start) +{ + struct dl *dl = fmsg_data->dl; + uint8_t value = nest_value; + int err; + + err = cmd_fmsg_nest_queue(fmsg_data, &value, start); + if (err != MNL_CB_OK) + return err; + + switch (value) { + case DEVLINK_ATTR_FMSG_OBJ_NEST_START: + if (start) + pr_out_entry_start(dl); + else + pr_out_entry_end(dl); + break; + case DEVLINK_ATTR_FMSG_PAIR_NEST_START: + break; + case DEVLINK_ATTR_FMSG_ARR_NEST_START: + if (dl->json_output) { + if (start) + jsonw_start_array(dl->jw); + else + jsonw_end_array(dl->jw); + } else { + if (start) { + __pr_out_newline(); + __pr_out_indent_inc(); + } else { + __pr_out_indent_dec(); + } + } + break; + default: + return -EINVAL; + } + return MNL_CB_OK; +} + +static int cmd_fmsg_object_cb(const struct nlmsghdr *nlh, void *data) +{ + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct fmsg_cb_data *fmsg_data = data; + struct dl *dl = fmsg_data->dl; + struct nlattr *nla_object; + int attr_type; + int err; + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_FMSG]) + return MNL_CB_ERROR; + + mnl_attr_for_each_nested(nla_object, tb[DEVLINK_ATTR_FMSG]) { + attr_type = mnl_attr_get_type(nla_object); + switch (attr_type) { + case DEVLINK_ATTR_FMSG_OBJ_NEST_START: + case DEVLINK_ATTR_FMSG_PAIR_NEST_START: + case DEVLINK_ATTR_FMSG_ARR_NEST_START: + err = cmd_fmsg_nest(fmsg_data, attr_type, true); + if (err != MNL_CB_OK) + return err; + break; + case DEVLINK_ATTR_FMSG_NEST_END: + err = cmd_fmsg_nest(fmsg_data, attr_type, false); + if (err != MNL_CB_OK) + return err; + break; + case DEVLINK_ATTR_FMSG_OBJ_NAME: + pr_out_name(dl, mnl_attr_get_str(nla_object)); + break; + case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE: + fmsg_data->value_type = mnl_attr_get_u8(nla_object); + break; + case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA: + err = fmsg_value_show(dl, fmsg_data->value_type, + nla_object); + if (err != MNL_CB_OK) + return err; + break; + default: + return -EINVAL; + } + } + return MNL_CB_OK; +} + +static int cmd_health_object_common(struct dl *dl, uint8_t cmd) +{ + struct fmsg_cb_data data; + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, cmd, NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, + DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0); + if (err) + return err; + + data.dl = dl; + TAILQ_INIT(&data.qhead); + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_fmsg_object_cb, &data); + return err; +} + +static int cmd_health_dump_show(struct dl *dl) +{ + return cmd_health_object_common(dl, DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET); +} + +static int cmd_health_diagnose(struct dl *dl) +{ + return cmd_health_object_common(dl, DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE); +} + +static int cmd_health_recover(struct dl *dl) +{ + struct nlmsghdr *nlh; + int err; + + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_RECOVER, + NLM_F_REQUEST | NLM_F_ACK); + + err = dl_argv_parse_put(nlh, dl, + DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0); + if (err) + return err; + + dl_opts_put(nlh, dl); + return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); +} + +enum devlink_health_reporter_state { + DEVLINK_HEALTH_REPORTER_STATE_HEALTHY, + DEVLINK_HEALTH_REPORTER_STATE_ERROR, +}; + +static const char *health_state_name(uint8_t state) +{ + switch (state) { + case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY: + return HEALTH_REPORTER_STATE_HEALTHY_STR; + case DEVLINK_HEALTH_REPORTER_STATE_ERROR: + return HEALTH_REPORTER_STATE_ERROR_STR; + default: + return ""; + } +} + +static void format_logtime(uint64_t time_ms, char *ts_date, char *ts_time) +{ + struct sysinfo s_info; + struct tm *info; + time_t now, sec; + int err; + + time(&now); + info = localtime(&now); + err = sysinfo(&s_info); + if (err) + goto out; + /* Subtract uptime in sec from now yields the time of system + * uptime. To this, add time_ms which is the amount of + * milliseconds elapsed between uptime and the dump taken. + */ + sec = now - s_info.uptime + time_ms / 1000; + info = localtime(&sec); +out: + strftime(ts_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info); + strftime(ts_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info); +} + +static void pr_out_health(struct dl *dl, struct nlattr **tb_health) +{ + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + enum devlink_health_reporter_state state; + const struct nlattr *attr; + uint64_t time_ms; + int err; + + err = mnl_attr_parse_nested(tb_health[DEVLINK_ATTR_HEALTH_REPORTER], + attr_cb, tb); + if (err != MNL_CB_OK) + return; + + if (!tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME] || + !tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] || + !tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] || + !tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE]) + return; + + pr_out_handle_start_arr(dl, tb_health); + + pr_out_str(dl, "name", + mnl_attr_get_str(tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME])); + if (!dl->json_output) { + __pr_out_newline(); + __pr_out_indent_inc(); + } + state = mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE]); + pr_out_str(dl, "state", health_state_name(state)); + pr_out_u64(dl, "error", + mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT])); + pr_out_u64(dl, "recover", + mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT])); + if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]) { + char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN]; + char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN]; + + attr = tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]; + time_ms = mnl_attr_get_u64(attr); + format_logtime(time_ms, dump_date, dump_time); + + pr_out_str(dl, "last_dump_date", dump_date); + pr_out_str(dl, "last_dump_time", dump_time); + } + if (tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]) + pr_out_u64(dl, "grace_period", + mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])); + if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]) + pr_out_bool(dl, "auto_recover", + mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])); + + __pr_out_indent_dec(); + pr_out_handle_end(dl); +} + +static int cmd_health_show_cb(const struct nlmsghdr *nlh, void *data) +{ + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct dl *dl = data; + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_HEALTH_REPORTER]) + return MNL_CB_ERROR; + + pr_out_health(dl, tb); + + return MNL_CB_OK; +} + +static int cmd_health_show(struct dl *dl) +{ + struct nlmsghdr *nlh; + uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; + int err; + + if (dl_argc(dl) == 0) + flags |= NLM_F_DUMP; + nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_GET, + flags); + + if (dl_argc(dl) > 0) { + err = dl_argv_parse_put(nlh, dl, + DL_OPT_HANDLE | + DL_OPT_HEALTH_REPORTER_NAME, 0); + if (err) + return err; + } + pr_out_section_start(dl, "health"); + + err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_health_show_cb, dl); + pr_out_section_end(dl); + return err; +} + +static void cmd_health_help(void) +{ + pr_err("Usage: devlink health show [ dev DEV reporter REPORTER_NAME ]\n"); + pr_err(" devlink health recover DEV reporter REPORTER_NAME\n"); + pr_err(" devlink health diagnose DEV reporter REPORTER_NAME\n"); + pr_err(" devlink health dump show DEV reporter REPORTER_NAME\n"); + pr_err(" devlink health dump clear DEV reporter REPORTER_NAME\n"); + pr_err(" devlink health set DEV reporter REPORTER_NAME { grace_period | auto_recover } { msec | boolean }\n"); +} + +static int cmd_health(struct dl *dl) +{ + if (dl_argv_match(dl, "help")) { + cmd_health_help(); + return 0; + } else if (dl_argv_match(dl, "show") || + dl_argv_match(dl, "list") || dl_no_arg(dl)) { + dl_arg_inc(dl); + return cmd_health_show(dl); + } else if (dl_argv_match(dl, "recover")) { + dl_arg_inc(dl); + return cmd_health_recover(dl); + } else if (dl_argv_match(dl, "diagnose")) { + dl_arg_inc(dl); + return cmd_health_diagnose(dl); + } else if (dl_argv_match(dl, "dump")) { + dl_arg_inc(dl); + if (dl_argv_match(dl, "show")) { + dl_arg_inc(dl); + return cmd_health_dump_show(dl); + } else if (dl_argv_match(dl, "clear")) { + dl_arg_inc(dl); + return cmd_health_dump_clear(dl); + } + } else if (dl_argv_match(dl, "set")) { + dl_arg_inc(dl); + return cmd_health_set_params(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +} + static void help(void) { pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" " devlink [ -f[orce] ] -b[atch] filename\n" - "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region }\n" + "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health }\n" " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] }\n"); } @@ -5590,6 +6314,9 @@ static int dl_cmd(struct dl *dl, int argc, char **argv) } else if (dl_argv_match(dl, "region")) { dl_arg_inc(dl); return cmd_region(dl); + } else if (dl_argv_match(dl, "health")) { + dl_arg_inc(dl); + return cmd_health(dl); } pr_err("Object \"%s\" not found\n", dl_argv(dl)); return -ENOENT; diff --git a/include/bpf_util.h b/include/bpf_util.h index 63837a04..63db07ca 100644 --- a/include/bpf_util.h +++ b/include/bpf_util.h @@ -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_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, size_t size_insns, const char *license, char *log, diff --git a/include/ll_map.h b/include/ll_map.h index 511fe00b..4de1041e 100644 --- a/include/ll_map.h +++ b/include/ll_map.h @@ -9,6 +9,7 @@ unsigned ll_name_to_index(const char *name); const char *ll_index_to_name(unsigned idx); int ll_index_to_type(unsigned idx); int ll_index_to_flags(unsigned idx); +void ll_drop_by_index(unsigned index); unsigned namehash(const char *str); const char *ll_idx_n2a(unsigned int idx); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index fb541e16..b7b748f1 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -14,6 +14,7 @@ /* Extended instruction set based on top of classic BPF */ /* instruction classes */ +#define BPF_JMP32 0x06 /* jmp mode in word width */ #define BPF_ALU64 0x07 /* alu mode in double word width */ /* ld/ldx fields */ @@ -266,6 +267,7 @@ enum bpf_attach_type { #define BPF_ANY 0 /* create new element or update existing */ #define BPF_NOEXIST 1 /* create new element if it didn't exist */ #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 */ #define BPF_F_NO_PREALLOC (1U << 0) @@ -2014,6 +2016,19 @@ union bpf_attr { * Only works if *skb* contains an IPv6 packet. Insert a * Segment Routing Header (**struct ipv6_sr_hdr**) inside * 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 * packet buffer. Therefore, at load time, all checks on pointers @@ -2327,6 +2342,23 @@ union bpf_attr { * "**y**". * Return * 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) \ FN(unspec), \ @@ -2421,7 +2453,11 @@ union bpf_attr { FN(map_peek_elem), \ FN(msg_push_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 * function eBPF program intends to call @@ -2494,7 +2530,8 @@ enum bpf_hdr_start_off { /* Encapsulation type for BPF_FUNC_lwt_push_encap helper. */ enum bpf_lwt_encap_mode { BPF_LWT_ENCAP_SEG6, - BPF_LWT_ENCAP_SEG6_INLINE + BPF_LWT_ENCAP_SEG6_INLINE, + BPF_LWT_ENCAP_IP, }; #define __bpf_md_ptr(type, name) \ @@ -2540,6 +2577,8 @@ struct __sk_buff { __bpf_md_ptr(struct bpf_flow_keys *, flow_keys); __u64 tstamp; __u32 wire_len; + __u32 gso_segs; + __bpf_md_ptr(struct bpf_sock *, sk); }; struct bpf_tunnel_key { @@ -2581,7 +2620,15 @@ enum bpf_ret_code { BPF_DROP = 2, /* 3-6 reserved */ 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 { @@ -2591,14 +2638,52 @@ struct bpf_sock { __u32 protocol; __u32 mark; __u32 priority; - __u32 src_ip4; /* Allows 1,2,4-byte read. - * Stored in network byte order. + /* IP address also allows 1 and 2 bytes access */ + __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. - * Stored in network byte order. + __u32 data_segs_in; /* RFC4898 tcpEStatsPerfDataSegsIn + * total number of data segments in. */ - __u32 src_port; /* Allows 4-byte read. - * Stored in host byte order + __u32 segs_out; /* RFC4898 tcpEStatsPerfSegsOut + * 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; }; +struct bpf_spin_lock { + __u32 val; +}; #endif /* __LINUX_BPF_H__ */ diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index d0a33d79..3b6a9e6b 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h @@ -89,6 +89,22 @@ enum devlink_command { DEVLINK_CMD_REGION_DEL, 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 */ __DEVLINK_CMD_MAX, DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 @@ -285,6 +301,37 @@ enum devlink_attr { DEVLINK_ATTR_REGION_CHUNK_ADDR, /* 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 */ __DEVLINK_ATTR_MAX, diff --git a/include/uapi/linux/icmpv6.h b/include/uapi/linux/icmpv6.h index cb247a5d..cf8d5d47 100644 --- a/include/uapi/linux/icmpv6.h +++ b/include/uapi/linux/icmpv6.h @@ -108,6 +108,8 @@ struct icmp6hdr { #define ICMPV6_MOBILE_PREFIX_SOL 146 #define ICMPV6_MOBILE_PREFIX_ADV 147 +#define ICMPV6_MRDISC_ADV 151 + /* * Codes for Destination Unreachable */ diff --git a/include/uapi/linux/if_bonding.h b/include/uapi/linux/if_bonding.h index 61a1bf6e..790585f0 100644 --- a/include/uapi/linux/if_bonding.h +++ b/include/uapi/linux/if_bonding.h @@ -117,6 +117,30 @@ struct ad_info { __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 */ /* diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 484ddf83..bfe7f9e6 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -923,6 +923,7 @@ enum { enum { LINK_XSTATS_TYPE_UNSPEC, LINK_XSTATS_TYPE_BRIDGE, + LINK_XSTATS_TYPE_BOND, __LINK_XSTATS_TYPE_MAX }; #define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h index 1d30d797..ac079abc 100644 --- a/include/uapi/linux/in.h +++ b/include/uapi/linux/in.h @@ -292,10 +292,11 @@ struct sockaddr_in { #define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) /* Defines for Multicast INADDR */ -#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */ -#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ -#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ -#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */ +#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */ +#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ +#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ +#define INADDR_ALLSNOOPERS_GROUP 0xe000006aU /* 224.0.0.106 */ +#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */ #endif /* contains the htonl type stuff.. */ diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 95d0db2a..51a0496f 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -63,12 +63,49 @@ enum { #define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2) #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*/ -enum { - TCA_ID_UNSPEC=0, - TCA_ID_POLICE=1, +enum tca_id { + TCA_ID_UNSPEC = 0, + 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 */ - __TCA_ID_MAX=255 + __TCA_ID_MAX = 255 }; #define TCA_ID_MAX __TCA_ID_MAX @@ -333,12 +370,19 @@ enum { /* Basic filter */ +struct tc_basic_pcnt { + __u64 rcnt; + __u64 rhit; +}; + enum { TCA_BASIC_UNSPEC, TCA_BASIC_CLASSID, TCA_BASIC_EMATCHES, TCA_BASIC_ACT, TCA_BASIC_POLICE, + TCA_BASIC_PCNT, + TCA_BASIC_PAD, __TCA_BASIC_MAX }; @@ -527,11 +571,17 @@ enum { /* Match-all classifier */ +struct tc_matchall_pcnt { + __u64 rhit; +}; + enum { TCA_MATCHALL_UNSPEC, TCA_MATCHALL_CLASSID, TCA_MATCHALL_ACT, TCA_MATCHALL_FLAGS, + TCA_MATCHALL_PCNT, + TCA_MATCHALL_PAD, __TCA_MATCHALL_MAX, }; diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 0d18b1d1..1eb572ef 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -954,7 +954,7 @@ enum { #define TCA_PIE_MAX (__TCA_PIE_MAX - 1) struct tc_pie_xstats { - __u32 prob; /* current probability */ + __u64 prob; /* current probability */ __u32 delay; /* current delay in ms */ __u32 avg_dq_rate; /* current average dq_rate in bits/pie_time */ __u32 packets_in; /* total number of packets enqueued */ diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h index e9970b69..c4bce0a2 100644 --- a/include/uapi/linux/sctp.h +++ b/include/uapi/linux/sctp.h @@ -59,6 +59,10 @@ 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 * SCTP . */ diff --git a/include/uapi/linux/tc_act/tc_bpf.h b/include/uapi/linux/tc_act/tc_bpf.h index 6e89a5df..653c4f94 100644 --- a/include/uapi/linux/tc_act/tc_bpf.h +++ b/include/uapi/linux/tc_act/tc_bpf.h @@ -13,8 +13,6 @@ #include -#define TCA_ACT_BPF 13 - struct tc_act_bpf { tc_gen; }; diff --git a/include/uapi/linux/tc_act/tc_connmark.h b/include/uapi/linux/tc_act/tc_connmark.h index 80caa47b..9f8f6f70 100644 --- a/include/uapi/linux/tc_act/tc_connmark.h +++ b/include/uapi/linux/tc_act/tc_connmark.h @@ -5,8 +5,6 @@ #include #include -#define TCA_ACT_CONNMARK 14 - struct tc_connmark { tc_gen; __u16 zone; diff --git a/include/uapi/linux/tc_act/tc_csum.h b/include/uapi/linux/tc_act/tc_csum.h index 0ecf4d29..94b20449 100644 --- a/include/uapi/linux/tc_act/tc_csum.h +++ b/include/uapi/linux/tc_act/tc_csum.h @@ -5,8 +5,6 @@ #include #include -#define TCA_ACT_CSUM 16 - enum { TCA_CSUM_UNSPEC, TCA_CSUM_PARMS, diff --git a/include/uapi/linux/tc_act/tc_gact.h b/include/uapi/linux/tc_act/tc_gact.h index 94273c3b..37e5392e 100644 --- a/include/uapi/linux/tc_act/tc_gact.h +++ b/include/uapi/linux/tc_act/tc_gact.h @@ -5,7 +5,6 @@ #include #include -#define TCA_ACT_GACT 5 struct tc_gact { tc_gen; diff --git a/include/uapi/linux/tc_act/tc_ife.h b/include/uapi/linux/tc_act/tc_ife.h index 2f48490e..8c401f18 100644 --- a/include/uapi/linux/tc_act/tc_ife.h +++ b/include/uapi/linux/tc_act/tc_ife.h @@ -6,7 +6,6 @@ #include #include -#define TCA_ACT_IFE 25 /* Flag bits for now just encoding/decoding; mutually exclusive */ #define IFE_ENCODE 1 #define IFE_DECODE 0 diff --git a/include/uapi/linux/tc_act/tc_ipt.h b/include/uapi/linux/tc_act/tc_ipt.h index b743c8bd..c48d7da6 100644 --- a/include/uapi/linux/tc_act/tc_ipt.h +++ b/include/uapi/linux/tc_act/tc_ipt.h @@ -4,9 +4,6 @@ #include -#define TCA_ACT_IPT 6 -#define TCA_ACT_XT 10 - enum { TCA_IPT_UNSPEC, TCA_IPT_TABLE, diff --git a/include/uapi/linux/tc_act/tc_mirred.h b/include/uapi/linux/tc_act/tc_mirred.h index 5dd671cf..2500a000 100644 --- a/include/uapi/linux/tc_act/tc_mirred.h +++ b/include/uapi/linux/tc_act/tc_mirred.h @@ -5,7 +5,6 @@ #include #include -#define TCA_ACT_MIRRED 8 #define TCA_EGRESS_REDIR 1 /* packet redirect to EGRESS*/ #define TCA_EGRESS_MIRROR 2 /* mirror packet to EGRESS */ #define TCA_INGRESS_REDIR 3 /* packet redirect to INGRESS*/ diff --git a/include/uapi/linux/tc_act/tc_nat.h b/include/uapi/linux/tc_act/tc_nat.h index 086be842..21399c2c 100644 --- a/include/uapi/linux/tc_act/tc_nat.h +++ b/include/uapi/linux/tc_act/tc_nat.h @@ -5,8 +5,6 @@ #include #include -#define TCA_ACT_NAT 9 - enum { TCA_NAT_UNSPEC, TCA_NAT_PARMS, diff --git a/include/uapi/linux/tc_act/tc_pedit.h b/include/uapi/linux/tc_act/tc_pedit.h index 24ec792d..f3e61b04 100644 --- a/include/uapi/linux/tc_act/tc_pedit.h +++ b/include/uapi/linux/tc_act/tc_pedit.h @@ -5,8 +5,6 @@ #include #include -#define TCA_ACT_PEDIT 7 - enum { TCA_PEDIT_UNSPEC, TCA_PEDIT_TM, diff --git a/include/uapi/linux/tc_act/tc_sample.h b/include/uapi/linux/tc_act/tc_sample.h index bd7e9f03..fee1bcc2 100644 --- a/include/uapi/linux/tc_act/tc_sample.h +++ b/include/uapi/linux/tc_act/tc_sample.h @@ -6,8 +6,6 @@ #include #include -#define TCA_ACT_SAMPLE 26 - struct tc_sample { tc_gen; }; diff --git a/include/uapi/linux/tc_act/tc_skbedit.h b/include/uapi/linux/tc_act/tc_skbedit.h index 6de6071e..800e9337 100644 --- a/include/uapi/linux/tc_act/tc_skbedit.h +++ b/include/uapi/linux/tc_act/tc_skbedit.h @@ -23,8 +23,6 @@ #include -#define TCA_ACT_SKBEDIT 11 - #define SKBEDIT_F_PRIORITY 0x1 #define SKBEDIT_F_QUEUE_MAPPING 0x2 #define SKBEDIT_F_MARK 0x4 diff --git a/include/uapi/linux/tc_act/tc_skbmod.h b/include/uapi/linux/tc_act/tc_skbmod.h index 38c072f6..c525b350 100644 --- a/include/uapi/linux/tc_act/tc_skbmod.h +++ b/include/uapi/linux/tc_act/tc_skbmod.h @@ -13,8 +13,6 @@ #include -#define TCA_ACT_SKBMOD 15 - #define SKBMOD_F_DMAC 0x1 #define SKBMOD_F_SMAC 0x2 #define SKBMOD_F_ETYPE 0x4 diff --git a/include/uapi/linux/tc_act/tc_tunnel_key.h b/include/uapi/linux/tc_act/tc_tunnel_key.h index be384d63..41c8b462 100644 --- a/include/uapi/linux/tc_act/tc_tunnel_key.h +++ b/include/uapi/linux/tc_act/tc_tunnel_key.h @@ -14,8 +14,6 @@ #include -#define TCA_ACT_TUNNEL_KEY 17 - #define TCA_TUNNEL_KEY_ACT_SET 1 #define TCA_TUNNEL_KEY_ACT_RELEASE 2 diff --git a/include/uapi/linux/tc_act/tc_vlan.h b/include/uapi/linux/tc_act/tc_vlan.h index 0d7b5fd6..168995b5 100644 --- a/include/uapi/linux/tc_act/tc_vlan.h +++ b/include/uapi/linux/tc_act/tc_vlan.h @@ -13,8 +13,6 @@ #include -#define TCA_ACT_VLAN 12 - #define TCA_VLAN_ACT_POP 1 #define TCA_VLAN_ACT_PUSH 2 #define TCA_VLAN_ACT_MODIFY 3 diff --git a/include/uapi/linux/xdp_diag.h b/include/uapi/linux/xdp_diag.h new file mode 100644 index 00000000..78b2591a --- /dev/null +++ b/include/uapi/linux/xdp_diag.h @@ -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 + +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 */ diff --git a/include/utils.h b/include/utils.h index 92bbe82d..8a9c3020 100644 --- a/include/utils.h +++ b/include/utils.h @@ -127,6 +127,14 @@ struct dn_naddr # define CLOCK_TAI 11 #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); int get_addr_1(inet_prefix *dst, const char *arg, int family); int get_prefix_1(inet_prefix *dst, char *arg, int family); diff --git a/ip/ip_common.h b/ip/ip_common.h index d67575c6..b4aa34a7 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -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_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 */ 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); diff --git a/ip/ipl2tp.c b/ip/ipl2tp.c index f699b258..77bc3249 100644 --- a/ip/ipl2tp.c +++ b/ip/ipl2tp.c @@ -237,9 +237,9 @@ static void print_tunnel(const struct l2tp_data *data) print_string(PRINT_FP, NULL, " UDP source / dest ports:", NULL); - print_uint(PRINT_ANY, "local_port", " %hu", + print_hu(PRINT_ANY, "local_port", " %hu", p->local_udp_port); - print_uint(PRINT_ANY, "peer_port", "/%hu", + print_hu(PRINT_ANY, "peer_port", "/%hu", p->peer_udp_port); print_nl(); diff --git a/ip/iplink.c b/ip/iplink.c index 3a0cf459..5a3c9613 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -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) return -2; + /* remove device from cache; next use can refresh with new data */ + ll_drop_by_index(req.i.ifi_index); + return 0; } diff --git a/ip/iplink_bond.c b/ip/iplink_bond.c index f906e7f1..c60f0e8a 100644 --- a/ip/iplink_bond.c +++ b/ip/iplink_bond.c @@ -13,16 +13,18 @@ #include #include #include -#include -#include -#include +#include #include "rt_names.h" #include "utils.h" #include "ip_common.h" +#include "json_print.h" #define BOND_MAX_ARP_TARGETS 16 +static unsigned int xstats_print_attr; +static int filter_index; + static const char *mode_tbl[] = { "balance-rr", "active-backup", @@ -649,10 +651,169 @@ static void bond_print_help(struct link_util *lu, int argc, char **argv, 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 = { .id = "bond", .maxattr = IFLA_BOND_MAX, .parse_opt = bond_parse_opt, .print_opt = bond_print_opt, .print_help = bond_print_help, + .parse_ifla_xstats = bond_parse_xstats, + .print_ifla_xstats = bond_print_xstats, }; diff --git a/ip/iplink_bond_slave.c b/ip/iplink_bond_slave.c index 67219c67..4eaf72b8 100644 --- a/ip/iplink_bond_slave.c +++ b/ip/iplink_bond_slave.c @@ -156,4 +156,6 @@ struct link_util bond_slave_link_util = { .print_opt = bond_slave_print_opt, .parse_opt = bond_slave_parse_opt, .print_help = bond_slave_print_help, + .parse_ifla_xstats = bond_parse_xstats, + .print_ifla_xstats = bond_print_xstats, }; diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index fbf8a79b..e9b77fdf 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -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); } -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 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]; 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 BRIDGE_XSTATS_MCAST: mstats = RTA_DATA(i); - ifname = ll_index_to_name(ifindex); - fprintf(f, "%-16s\n", ifname); - fprintf(f, "%-16s IGMP queries:\n", ""); - fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n", - "", - mstats->igmp_v1queries[BR_MCAST_DIR_RX], - mstats->igmp_v2queries[BR_MCAST_DIR_RX], - mstats->igmp_v3queries[BR_MCAST_DIR_RX]); - fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n", - "", - mstats->igmp_v1queries[BR_MCAST_DIR_TX], - mstats->igmp_v2queries[BR_MCAST_DIR_TX], - mstats->igmp_v3queries[BR_MCAST_DIR_TX]); + open_json_object("multicast"); + open_json_object("igmp_queries"); + print_string(PRINT_FP, NULL, + "%-16s IGMP queries:\n", ""); + print_string(PRINT_FP, NULL, "%-16s ", ""); + print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ", + mstats->igmp_v1queries[BR_MCAST_DIR_RX]); + print_u64(PRINT_ANY, "rx_v2", "v2 %llu ", + mstats->igmp_v2queries[BR_MCAST_DIR_RX]); + print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n", + mstats->igmp_v3queries[BR_MCAST_DIR_RX]); + print_string(PRINT_FP, NULL, "%-16s ", ""); + 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", ""); - fprintf(f, "%-16s RX: v1 %llu v2 %llu v3 %llu\n", - "", - mstats->igmp_v1reports[BR_MCAST_DIR_RX], - mstats->igmp_v2reports[BR_MCAST_DIR_RX], - mstats->igmp_v3reports[BR_MCAST_DIR_RX]); - fprintf(f, "%-16s TX: v1 %llu v2 %llu v3 %llu\n", - "", - mstats->igmp_v1reports[BR_MCAST_DIR_TX], - mstats->igmp_v2reports[BR_MCAST_DIR_TX], - mstats->igmp_v3reports[BR_MCAST_DIR_TX]); + open_json_object("igmp_reports"); + print_string(PRINT_FP, NULL, + "%-16s IGMP reports:\n", ""); + print_string(PRINT_FP, NULL, "%-16s ", ""); + print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ", + mstats->igmp_v1reports[BR_MCAST_DIR_RX]); + print_u64(PRINT_ANY, "rx_v2", "v2 %llu ", + mstats->igmp_v2reports[BR_MCAST_DIR_RX]); + print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n", + mstats->igmp_v3reports[BR_MCAST_DIR_RX]); + 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", - "", - mstats->igmp_leaves[BR_MCAST_DIR_RX], - mstats->igmp_leaves[BR_MCAST_DIR_TX]); + open_json_object("igmp_leaves"); + print_string(PRINT_FP, NULL, + "%-16s IGMP leaves: ", ""); + 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", - "", mstats->igmp_parse_errors); + print_string(PRINT_FP, NULL, + "%-16s IGMP parse errors: ", ""); + print_u64(PRINT_ANY, "igmp_parse_errors", "%llu\n", + mstats->igmp_parse_errors); - fprintf(f, "%-16s MLD queries:\n", ""); - fprintf(f, "%-16s RX: v1 %llu v2 %llu\n", - "", - mstats->mld_v1queries[BR_MCAST_DIR_RX], - mstats->mld_v2queries[BR_MCAST_DIR_RX]); - fprintf(f, "%-16s TX: v1 %llu v2 %llu\n", - "", - mstats->mld_v1queries[BR_MCAST_DIR_TX], - mstats->mld_v2queries[BR_MCAST_DIR_TX]); + open_json_object("mld_queries"); + print_string(PRINT_FP, NULL, + "%-16s MLD queries:\n", ""); + print_string(PRINT_FP, NULL, "%-16s ", ""); + print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ", + mstats->mld_v1queries[BR_MCAST_DIR_RX]); + print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n", + mstats->mld_v2queries[BR_MCAST_DIR_RX]); + 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", ""); - fprintf(f, "%-16s RX: v1 %llu v2 %llu\n", - "", - mstats->mld_v1reports[BR_MCAST_DIR_RX], - mstats->mld_v2reports[BR_MCAST_DIR_RX]); - fprintf(f, "%-16s TX: v1 %llu v2 %llu\n", - "", - mstats->mld_v1reports[BR_MCAST_DIR_TX], - mstats->mld_v2reports[BR_MCAST_DIR_TX]); + open_json_object("mld_reports"); + print_string(PRINT_FP, NULL, + "%-16s MLD reports:\n", ""); + print_string(PRINT_FP, NULL, "%-16s ", ""); + print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ", + mstats->mld_v1reports[BR_MCAST_DIR_RX]); + print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n", + mstats->mld_v2reports[BR_MCAST_DIR_RX]); + 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", - "", - mstats->mld_leaves[BR_MCAST_DIR_RX], - mstats->mld_leaves[BR_MCAST_DIR_TX]); + open_json_object("mld_leaves"); + print_string(PRINT_FP, NULL, + "%-16s MLD leaves: ", ""); + 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", - "", mstats->mld_parse_errors); + print_string(PRINT_FP, NULL, + "%-16s MLD parse errors: ", ""); + print_u64(PRINT_ANY, "mld_parse_errors", "%llu\n", + mstats->mld_parse_errors); + close_json_object(); break; } } + close_json_object(); } 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 rtattr *tb[IFLA_STATS_MAX+1]; int len = n->nlmsg_len; - FILE *fp = arg; len -= NLMSG_LENGTH(sizeof(*ifsm)); 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); 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); 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); return 0; diff --git a/ip/iplink_xstats.c b/ip/iplink_xstats.c index 908d9228..c64e6885 100644 --- a/ip/iplink_xstats.c +++ b/ip/iplink_xstats.c @@ -70,10 +70,13 @@ int iplink_ifla_xstats(int argc, char **argv) return -1; } + new_json_obj(json); if (rtnl_dump_filter(&rth, lu->print_ifla_xstats, stdout) < 0) { + delete_json_obj(); fprintf(stderr, "Dump terminated\n"); return -1; } + delete_json_obj(); return 0; } diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 03879b49..430d8844 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -28,6 +28,7 @@ static int usage(void) { fprintf(stderr, "Usage: ip netns list\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 [-all] netns delete [NAME]\n"); fprintf(stderr, " ip netns identify [PID]\n"); @@ -632,24 +633,40 @@ static int create_netns_dir(void) 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 * a new mount namespace and bind them into a well known * 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 * 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; + pid_t pid; int fd; int made_netns_run_dir_mount = 0; - if (argc < 1) { - fprintf(stderr, "No netns name specified\n"); - return -1; + if (create) { + if (argc < 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]; @@ -689,21 +706,33 @@ static int netns_add(int argc, char **argv) return -1; } close(fd); - if (unshare(CLONE_NEWNET) < 0) { - fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n", - name, strerror(errno)); - goto out_delete; + + if (create) { + if (unshare(CLONE_NEWNET) < 0) { + 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 */ - if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) { - fprintf(stderr, "Bind /proc/self/ns/net -> %s failed: %s\n", - netns_path, strerror(errno)); + if (mount(proc_path, netns_path, "none", MS_BIND, NULL) < 0) { + fprintf(stderr, "Bind %s -> %s failed: %s\n", + proc_path, netns_path, strerror(errno)); goto out_delete; } return 0; 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; } @@ -846,7 +875,7 @@ int do_netns(int argc, char **argv) return usage(); 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) return netns_set(argc-1, argv+1); @@ -866,6 +895,9 @@ int do_netns(int argc, char **argv) if (matches(*argv, "monitor") == 0) 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); exit(-1); } diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c index 2dea4e37..b153b863 100644 --- a/ip/ipxfrm.c +++ b/ip/ipxfrm.c @@ -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, - FILE *fp, const char *prefix, int newline) + FILE *fp, const char *prefix, int newline, + bool nokeys) { int keylen; int i; @@ -521,7 +522,9 @@ static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len, goto fin; } - if (keylen > 0) { + if (nokeys) + fprintf(fp, "<