diff --git a/bridge/br_common.h b/bridge/br_common.h index b5798da3..b9adafd9 100644 --- a/bridge/br_common.h +++ b/bridge/br_common.h @@ -10,6 +10,9 @@ void print_vlan_info(struct rtattr *tb, int ifindex); int print_linkinfo(struct nlmsghdr *n, void *arg); int print_mdb_mon(struct nlmsghdr *n, void *arg); int print_fdb(struct nlmsghdr *n, void *arg); +void print_stp_state(__u8 state); +int parse_stp_state(const char *arg); +int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor); int do_fdb(int argc, char **argv); int do_mdb(int argc, char **argv); diff --git a/bridge/link.c b/bridge/link.c index d88c469d..205a2fe7 100644 --- a/bridge/link.c +++ b/bridge/link.c @@ -19,7 +19,7 @@ static unsigned int filter_index; -static const char *port_states[] = { +static const char *stp_states[] = { [BR_STATE_DISABLED] = "disabled", [BR_STATE_LISTENING] = "listening", [BR_STATE_LEARNING] = "learning", @@ -68,16 +68,31 @@ static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown) close_json_array(PRINT_ANY, "> "); } -static void print_portstate(__u8 state) +void print_stp_state(__u8 state) { if (state <= BR_STATE_BLOCKING) print_string(PRINT_ANY, "state", - "state %s ", port_states[state]); + "state %s ", stp_states[state]); else print_uint(PRINT_ANY, "state", "state (%d) ", state); } +int parse_stp_state(const char *arg) +{ + size_t nstates = ARRAY_SIZE(stp_states); + int state; + + for (state = 0; state < nstates; state++) + if (strcmp(stp_states[state], arg) == 0) + break; + + if (state == nstates) + state = -1; + + return state; +} + static void print_hwmode(__u16 mode) { if (mode >= ARRAY_SIZE(hw_mode)) @@ -96,7 +111,7 @@ static void print_protinfo(FILE *fp, struct rtattr *attr) parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, attr); if (prtb[IFLA_BRPORT_STATE]) - print_portstate(rta_getattr_u8(prtb[IFLA_BRPORT_STATE])); + print_stp_state(rta_getattr_u8(prtb[IFLA_BRPORT_STATE])); if (prtb[IFLA_BRPORT_PRIORITY]) print_uint(PRINT_ANY, "priority", @@ -161,7 +176,7 @@ static void print_protinfo(FILE *fp, struct rtattr *attr) print_on_off(PRINT_ANY, "isolated", "isolated %s ", rta_getattr_u8(prtb[IFLA_BRPORT_ISOLATED])); } else - print_portstate(rta_getattr_u8(attr)); + print_stp_state(rta_getattr_u8(attr)); } @@ -359,14 +374,11 @@ static int brlink_modify(int argc, char **argv) } else if (strcmp(*argv, "state") == 0) { NEXT_ARG(); char *endptr; - size_t nstates = ARRAY_SIZE(port_states); state = strtol(*argv, &endptr, 10); if (!(**argv != '\0' && *endptr == '\0')) { - for (state = 0; state < nstates; state++) - if (strcasecmp(port_states[state], *argv) == 0) - break; - if (state == nstates) { + state = parse_stp_state(*argv); + if (state == -1) { fprintf(stderr, "Error: invalid STP port state\n"); return -1; diff --git a/bridge/mdb.c b/bridge/mdb.c index ef89258b..b427d878 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -16,9 +16,9 @@ #include #include "libnetlink.h" +#include "utils.h" #include "br_common.h" #include "rt_names.h" -#include "utils.h" #include "json_print.h" #ifndef MDBA_RTA diff --git a/bridge/monitor.c b/bridge/monitor.c index 08439a60..88f52f52 100644 --- a/bridge/monitor.c +++ b/bridge/monitor.c @@ -31,7 +31,7 @@ static int prefix_banner; static void usage(void) { - fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | all]\n"); + fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | vlan | all]\n"); exit(-1); } @@ -67,6 +67,12 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl, print_nlmsg_timestamp(fp, n); return 0; + case RTM_NEWVLAN: + case RTM_DELVLAN: + if (prefix_banner) + fprintf(fp, "[VLAN]"); + return print_vlan_rtm(n, arg, true); + default: return 0; } @@ -79,6 +85,7 @@ int do_monitor(int argc, char **argv) int llink = 0; int lneigh = 0; int lmdb = 0; + int lvlan = 0; rtnl_close(&rth); @@ -95,8 +102,12 @@ int do_monitor(int argc, char **argv) } else if (matches(*argv, "mdb") == 0) { lmdb = 1; groups = 0; + } else if (matches(*argv, "vlan") == 0) { + lvlan = 1; + groups = 0; } else if (strcmp(*argv, "all") == 0) { groups = ~RTMGRP_TC; + lvlan = 1; prefix_banner = 1; } else if (matches(*argv, "help") == 0) { usage(); @@ -134,6 +145,12 @@ int do_monitor(int argc, char **argv) if (rtnl_open(&rth, groups) < 0) exit(1); + + if (lvlan && rtnl_add_nl_group(&rth, RTNLGRP_BRVLAN) < 0) { + fprintf(stderr, "Failed to add bridge vlan group to list\n"); + exit(1); + } + ll_init_map(&rth); if (rtnl_listen(&rth, accept_msg, stdout) < 0) diff --git a/bridge/vlan.c b/bridge/vlan.c index 0d142bc9..9b6511f1 100644 --- a/bridge/vlan.c +++ b/bridge/vlan.c @@ -16,6 +16,7 @@ #include "utils.h" static unsigned int filter_index, filter_vlan; +static int vlan_rtm_cur_ifidx = -1; enum vlan_show_subject { VLAN_SHOW_VLAN, @@ -33,6 +34,7 @@ static void usage(void) "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ tunnel_info id TUNNEL_ID ]\n" " [ pvid ] [ untagged ]\n" " [ self ] [ master ]\n" + " bridge vlan { set } vid VLAN_ID dev DEV [ state STP_STATE ]\n" " bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n" " bridge vlan { tunnelshow } [ dev DEV ] [ vid VLAN_ID ]\n"); exit(-1); @@ -241,6 +243,100 @@ static int vlan_modify(int cmd, int argc, char **argv) return 0; } +static int vlan_option_set(int argc, char **argv) +{ + struct { + struct nlmsghdr n; + struct br_vlan_msg bvm; + char buf[1024]; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_NEWVLAN, + .bvm.family = PF_BRIDGE, + }; + struct bridge_vlan_info vinfo = {}; + struct rtattr *afspec; + short vid_end = -1; + char *d = NULL; + short vid = -1; + int state = -1; + + while (argc > 0) { + if (strcmp(*argv, "dev") == 0) { + NEXT_ARG(); + d = *argv; + } else if (strcmp(*argv, "vid") == 0) { + char *p; + + NEXT_ARG(); + p = strchr(*argv, '-'); + if (p) { + *p = '\0'; + p++; + vid = atoi(*argv); + vid_end = atoi(p); + if (vid >= vid_end || vid_end >= 4096) { + fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n", + vid, vid_end); + return -1; + } + } else { + vid = atoi(*argv); + } + } else if (strcmp(*argv, "state") == 0) { + char *endptr; + + NEXT_ARG(); + state = strtol(*argv, &endptr, 10); + if (!(**argv != '\0' && *endptr == '\0')) + state = parse_stp_state(*argv); + if (state == -1) { + fprintf(stderr, "Error: invalid STP state\n"); + return -1; + } + } else { + if (matches(*argv, "help") == 0) + NEXT_ARG(); + } + argc--; argv++; + } + + if (d == NULL || vid == -1) { + fprintf(stderr, "Device and VLAN ID are required arguments.\n"); + return -1; + } + + req.bvm.ifindex = ll_name_to_index(d); + if (req.bvm.ifindex == 0) { + fprintf(stderr, "Cannot find network device \"%s\"\n", d); + return -1; + } + + if (vid >= 4096) { + fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid); + return -1; + } + afspec = addattr_nest(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY); + afspec->rta_type |= NLA_F_NESTED; + + vinfo.flags = BRIDGE_VLAN_INFO_ONLY_OPTS; + vinfo.vid = vid; + addattr_l(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_INFO, &vinfo, + sizeof(vinfo)); + if (vid_end != -1) + addattr16(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_RANGE, + vid_end); + if (state >= 0) + addattr8(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_STATE, state); + addattr_nest_end(&req.n, afspec); + + if (rtnl_talk(&rth, &req.n, NULL) < 0) + return -1; + + return 0; +} + /* In order to use this function for both filtering and non-filtering cases * we need to make it a tristate: * return -1 - if filtering we've gone over so don't continue @@ -422,14 +518,8 @@ static void print_vlan_flags(__u16 flags) close_json_array(PRINT_JSON, NULL); } -static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats) +static void __print_one_vlan_stats(const struct bridge_vlan_xstats *vstats) { - open_json_object(NULL); - - print_hu(PRINT_ANY, "vid", "%hu", vstats->vid); - print_vlan_flags(vstats->flags); - print_nl(); - print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", ""); print_lluint(PRINT_ANY, "rx_bytes", "RX: %llu bytes", vstats->rx_bytes); @@ -441,6 +531,16 @@ static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats) vstats->tx_bytes); print_lluint(PRINT_ANY, "tx_packets", " %llu packets\n", vstats->tx_packets); +} + +static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats) +{ + open_json_object(NULL); + + print_hu(PRINT_ANY, "vid", "%hu", vstats->vid); + print_vlan_flags(vstats->flags); + print_nl(); + __print_one_vlan_stats(vstats); close_json_object(); } @@ -521,6 +621,115 @@ static int print_vlan_stats(struct nlmsghdr *n, void *arg) return 0; } +int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor) +{ + struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1], *a; + struct br_vlan_msg *bvm = NLMSG_DATA(n); + int len = n->nlmsg_len; + int rem; + + if (n->nlmsg_type != RTM_NEWVLAN && n->nlmsg_type != RTM_DELVLAN && + n->nlmsg_type != RTM_GETVLAN) { + fprintf(stderr, "Unknown vlan rtm message: %08x %08x %08x\n", + n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); + return 0; + } + + len -= NLMSG_LENGTH(sizeof(*bvm)); + if (len < 0) { + fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); + return -1; + } + + if (bvm->family != AF_BRIDGE) + return 0; + + if (filter_index && filter_index != bvm->ifindex) + return 0; + + if (n->nlmsg_type == RTM_DELVLAN) + print_bool(PRINT_ANY, "deleted", "Deleted ", true); + + if (monitor) + vlan_rtm_cur_ifidx = -1; + + if (vlan_rtm_cur_ifidx != -1 && vlan_rtm_cur_ifidx != bvm->ifindex) { + close_vlan_port(); + vlan_rtm_cur_ifidx = -1; + } + + rem = len; + for (a = BRVLAN_RTA(bvm); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) { + struct bridge_vlan_xstats vstats; + struct bridge_vlan_info *vinfo; + __u32 vrange = 0; + __u8 state = 0; + + parse_rtattr_flags(vtb, BRIDGE_VLANDB_ENTRY_MAX, RTA_DATA(a), + RTA_PAYLOAD(a), NLA_F_NESTED); + vinfo = RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_INFO]); + + memset(&vstats, 0, sizeof(vstats)); + if (vtb[BRIDGE_VLANDB_ENTRY_RANGE]) + vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_ENTRY_RANGE]); + else + vrange = vinfo->vid; + + if (vtb[BRIDGE_VLANDB_ENTRY_STATE]) + state = rta_getattr_u8(vtb[BRIDGE_VLANDB_ENTRY_STATE]); + + if (vtb[BRIDGE_VLANDB_ENTRY_STATS]) { + struct rtattr *stb[BRIDGE_VLANDB_STATS_MAX+1]; + struct rtattr *attr; + + attr = vtb[BRIDGE_VLANDB_ENTRY_STATS]; + parse_rtattr(stb, BRIDGE_VLANDB_STATS_MAX, RTA_DATA(attr), + RTA_PAYLOAD(attr)); + + if (stb[BRIDGE_VLANDB_STATS_RX_BYTES]) { + attr = stb[BRIDGE_VLANDB_STATS_RX_BYTES]; + vstats.rx_bytes = rta_getattr_u64(attr); + } + if (stb[BRIDGE_VLANDB_STATS_RX_PACKETS]) { + attr = stb[BRIDGE_VLANDB_STATS_RX_PACKETS]; + vstats.rx_packets = rta_getattr_u64(attr); + } + if (stb[BRIDGE_VLANDB_STATS_TX_PACKETS]) { + attr = stb[BRIDGE_VLANDB_STATS_TX_PACKETS]; + vstats.tx_packets = rta_getattr_u64(attr); + } + if (stb[BRIDGE_VLANDB_STATS_TX_BYTES]) { + attr = stb[BRIDGE_VLANDB_STATS_TX_BYTES]; + vstats.tx_bytes = rta_getattr_u64(attr); + } + } + if (vlan_rtm_cur_ifidx != bvm->ifindex) { + open_vlan_port(bvm->ifindex, VLAN_SHOW_VLAN); + open_json_object(NULL); + vlan_rtm_cur_ifidx = bvm->ifindex; + } else { + open_json_object(NULL); + print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", ""); + } + print_range("vlan", vinfo->vid, vrange); + print_vlan_flags(vinfo->flags); + print_nl(); + print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", ""); + print_stp_state(state); + print_nl(); + if (show_stats) + __print_one_vlan_stats(&vstats); + close_json_object(); + } + + return 0; +} + +static int print_vlan_rtm_filter(struct nlmsghdr *n, void *arg) +{ + return print_vlan_rtm(n, arg, false); +} + static int vlan_show(int argc, char **argv, int subject) { char *filter_dev = NULL; @@ -549,6 +758,34 @@ static int vlan_show(int argc, char **argv, int subject) new_json_obj(json); + /* if show_details is true then use the new bridge vlan dump format */ + if (show_details && subject == VLAN_SHOW_VLAN) { + __u32 dump_flags = show_stats ? BRIDGE_VLANDB_DUMPF_STATS : 0; + + if (rtnl_brvlandump_req(&rth, PF_BRIDGE, dump_flags) < 0) { + perror("Cannot send dump request"); + exit(1); + } + + if (!is_json_context()) { + printf("%-" __stringify(IFNAMSIZ) "s %-" + __stringify(VLAN_ID_LEN) "s", "port", + "vlan-id"); + printf("\n"); + } + + ret = rtnl_dump_filter(&rth, print_vlan_rtm_filter, &subject); + if (ret < 0) { + fprintf(stderr, "Dump terminated\n"); + exit(1); + } + + if (vlan_rtm_cur_ifidx != -1) + close_vlan_port(); + + goto out; + } + if (!show_stats) { if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE, (compress_vlans ? @@ -602,6 +839,7 @@ static int vlan_show(int argc, char **argv, int subject) } } +out: delete_json_obj(); fflush(stdout); return 0; @@ -667,6 +905,8 @@ int do_vlan(int argc, char **argv) if (matches(*argv, "tunnelshow") == 0) { return vlan_show(argc-1, argv+1, VLAN_SHOW_TUNNELINFO); } + if (matches(*argv, "set") == 0) + return vlan_option_set(argc-1, argv+1); if (matches(*argv, "help") == 0) usage(); } else { diff --git a/devlink/devlink.c b/devlink/devlink.c index faa87b3d..0b5548fb 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -39,6 +39,7 @@ #include "version.h" #include "list.h" #include "mnlg.h" +#include "mnl_utils.h" #include "json_print.h" #include "utils.h" #include "namespace.h" @@ -148,24 +149,11 @@ static void __pr_out_newline(void) g_new_line_count++; } -static int _mnlg_socket_recv_run(struct mnlg_socket *nlg, - mnl_cb_t data_cb, void *data) -{ - int err; - - err = mnlg_socket_recv_run(nlg, data_cb, data); - if (err < 0) { - pr_err("devlink answers: %s\n", strerror(errno)); - return -errno; - } - return 0; -} - static void dummy_signal_handler(int signum) { } -static int _mnlg_socket_recv_run_intr(struct mnlg_socket *nlg, +static int _mnlg_socket_recv_run_intr(struct mnlu_gen_socket *nlg, mnl_cb_t data_cb, void *data) { struct sigaction act, oact; @@ -176,7 +164,7 @@ static int _mnlg_socket_recv_run_intr(struct mnlg_socket *nlg, act.sa_flags = SA_NODEFER; sigaction(SIGINT, &act, &oact); - err = mnlg_socket_recv_run(nlg, data_cb, data); + err = mnlu_gen_socket_recv_run(nlg, data_cb, data); sigaction(SIGINT, &oact, NULL); if (err < 0 && errno != EINTR) { pr_err("devlink answers: %s\n", strerror(errno)); @@ -185,7 +173,7 @@ static int _mnlg_socket_recv_run_intr(struct mnlg_socket *nlg, return 0; } -static int _mnlg_socket_send(struct mnlg_socket *nlg, +static int _mnlg_socket_send(struct mnlu_gen_socket *nlg, const struct nlmsghdr *nlh) { int err; @@ -198,19 +186,7 @@ static int _mnlg_socket_send(struct mnlg_socket *nlg, return 0; } -static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg, - const struct nlmsghdr *nlh, - mnl_cb_t data_cb, void *data) -{ - int err; - - err = _mnlg_socket_send(nlg, nlh); - if (err) - return err; - return _mnlg_socket_recv_run(nlg, data_cb, data); -} - -static int _mnlg_socket_group_add(struct mnlg_socket *nlg, +static int _mnlg_socket_group_add(struct mnlu_gen_socket *nlg, const char *group_name) { int err; @@ -367,7 +343,7 @@ struct dl_opts { }; struct dl { - struct mnlg_socket *nlg; + struct mnlu_gen_socket nlg; struct list_head ifname_map_list; int argc; char **argv; @@ -821,10 +797,11 @@ static int ifname_map_init(struct dl *dl) INIT_LIST_HEAD(&dl->ifname_map_list); - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, + + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_GET, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, ifname_map_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, ifname_map_cb, dl); if (err) { ifname_map_fini(dl); return err; @@ -866,31 +843,6 @@ static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name, return -ENOENT; } -static unsigned int strslashcount(char *str) -{ - unsigned int count = 0; - char *pos = str; - - while ((pos = strchr(pos, '/'))) { - count++; - pos++; - } - return count; -} - -static int strslashrsplit(char *str, char **before, char **after) -{ - char *slash; - - slash = strrchr(str, '/'); - if (!slash) - return -EINVAL; - *slash = '\0'; - *before = str; - *after = slash + 1; - return 0; -} - static int strtouint64_t(const char *str, uint64_t *p_val) { char *endptr; @@ -967,7 +919,7 @@ static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name) { int err; - err = strslashrsplit(str, p_bus_name, p_dev_name); + err = str_split_by_char(str, p_bus_name, p_dev_name, '/'); if (err) { pr_err("Devlink identification (\"bus_name/dev_name\") \"%s\" is invalid\n", str); return err; @@ -983,7 +935,7 @@ static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name) pr_err("Devlink identification (\"bus_name/dev_name\") expected\n"); return -EINVAL; } - if (strslashcount(str) != 1) { + if (get_str_char_count(str, '/') != 1) { pr_err("Wrong devlink identification string format.\n"); pr_err("Expected \"bus_name/dev_name\".\n"); return -EINVAL; @@ -999,7 +951,7 @@ static int __dl_argv_handle_port(char *str, char *portstr; int err; - err = strslashrsplit(str, &handlestr, &portstr); + err = str_split_by_char(str, &handlestr, &portstr, '/'); if (err) { pr_err("Port identification \"%s\" is invalid\n", str); return err; @@ -1010,7 +962,7 @@ static int __dl_argv_handle_port(char *str, portstr); return err; } - err = strslashrsplit(handlestr, p_bus_name, p_dev_name); + err = str_split_by_char(handlestr, p_bus_name, p_dev_name, '/'); if (err) { pr_err("Port identification \"%s\" is invalid\n", str); return err; @@ -1043,7 +995,7 @@ static int dl_argv_handle_port(struct dl *dl, char **p_bus_name, pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n"); return -EINVAL; } - slash_count = strslashcount(str); + slash_count = get_str_char_count(str, '/'); switch (slash_count) { case 0: return __dl_argv_handle_port_ifname(dl, str, p_bus_name, @@ -1072,7 +1024,7 @@ static int dl_argv_handle_both(struct dl *dl, char **p_bus_name, "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n"); return -EINVAL; } - slash_count = strslashcount(str); + slash_count = get_str_char_count(str, '/'); if (slash_count == 1) { err = __dl_argv_handle(str, p_bus_name, p_dev_name); if (err) @@ -1104,12 +1056,12 @@ static int __dl_argv_handle_region(char *str, char **p_bus_name, char *handlestr; int err; - err = strslashrsplit(str, &handlestr, p_region); + err = str_split_by_char(str, &handlestr, p_region, '/'); if (err) { pr_err("Region identification \"%s\" is invalid\n", str); return err; } - err = strslashrsplit(handlestr, p_bus_name, p_dev_name); + err = str_split_by_char(handlestr, p_bus_name, p_dev_name, '/'); if (err) { pr_err("Region identification \"%s\" is invalid\n", str); return err; @@ -1128,7 +1080,7 @@ static int dl_argv_handle_region(struct dl *dl, char **p_bus_name, return -EINVAL; } - slash_count = strslashcount(str); + slash_count = get_str_char_count(str, '/'); if (slash_count != 2) { pr_err("Wrong region identification string format.\n"); pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n"); @@ -1426,8 +1378,10 @@ static int port_flavour_parse(const char *flavour, uint16_t *value) int num; num = str_map_lookup_str(port_flavour_map, flavour); - if (num < 0) + if (num < 0) { + invarg("unknown flavour", flavour); return num; + } *value = num; return 0; } @@ -1437,8 +1391,10 @@ static int port_fn_state_parse(const char *statestr, uint8_t *state) int num; num = str_map_lookup_str(port_fn_state_map, statestr); - if (num < 0) + if (num < 0) { + invarg("unknown state", statestr); return num; + } *state = num; return 0; } @@ -2581,7 +2537,7 @@ static int cmd_dev_eswitch_show(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_GET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_ESWITCH_GET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0); @@ -2589,7 +2545,7 @@ static int cmd_dev_eswitch_show(struct dl *dl) return err; pr_out_section_start(dl, "dev"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_eswitch_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_eswitch_show_cb, dl); pr_out_section_end(dl); return err; } @@ -2599,7 +2555,7 @@ static int cmd_dev_eswitch_set(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_ESWITCH_SET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, @@ -2615,7 +2571,7 @@ static int cmd_dev_eswitch_set(struct dl *dl) return -ENOENT; } - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_dev_eswitch(struct dl *dl) @@ -2979,16 +2935,16 @@ static int cmd_dev_param_set(struct dl *dl) return err; /* Get value type */ - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_GET, NLM_F_REQUEST | NLM_F_ACK); dl_opts_put(nlh, dl); ctx.dl = dl; - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_set_cb, &ctx); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_param_set_cb, &ctx); if (err) return err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_SET, NLM_F_REQUEST | NLM_F_ACK); dl_opts_put(nlh, dl); @@ -3066,7 +3022,7 @@ static int cmd_dev_param_set(struct dl *dl) printf("Value type not supported\n"); return -ENOTSUP; } - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); err_param_value_parse: pr_err("Value \"%s\" is not a number or not within range\n", @@ -3098,7 +3054,7 @@ static int cmd_dev_param_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | @@ -3108,7 +3064,7 @@ static int cmd_dev_param_show(struct dl *dl) } pr_out_section_start(dl, "param"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_param_show_cb, dl); pr_out_section_end(dl); return err; } @@ -3254,7 +3210,7 @@ static int cmd_dev_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0); @@ -3263,7 +3219,7 @@ static int cmd_dev_show(struct dl *dl) } pr_out_section_start(dl, "dev"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_show_cb, dl); pr_out_section_end(dl); return err; } @@ -3329,7 +3285,7 @@ static int cmd_dev_reload(struct dl *dl) return 0; } - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RELOAD, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RELOAD, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, @@ -3338,7 +3294,7 @@ static int cmd_dev_reload(struct dl *dl) if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_reload_cb, dl); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_reload_cb, dl); } static void pr_out_versions_single(struct dl *dl, const struct nlmsghdr *nlh, @@ -3474,7 +3430,7 @@ static int cmd_dev_info(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_INFO_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_INFO_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0); @@ -3483,7 +3439,7 @@ static int cmd_dev_info(struct dl *dl) } pr_out_section_start(dl, "info"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_versions_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_versions_show_cb, dl); pr_out_section_end(dl); return err; } @@ -3668,7 +3624,7 @@ static void cmd_dev_flash_time_elapsed(struct cmd_dev_flash_status_ctx *ctx) } static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx *ctx, - struct mnlg_socket *nlg_ntf, + struct mnlu_gen_socket *nlg_ntf, int pipe_r) { int nlfd = mnlg_socket_get_fd(nlg_ntf); @@ -3701,8 +3657,8 @@ static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx *ctx, return -errno; } if (FD_ISSET(nlfd, &fds[0])) { - err = _mnlg_socket_recv_run(nlg_ntf, - cmd_dev_flash_status_cb, ctx); + err = mnlu_gen_socket_recv_run(nlg_ntf, + cmd_dev_flash_status_cb, ctx); if (err) return err; } @@ -3724,7 +3680,7 @@ static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx *ctx, static int cmd_dev_flash(struct dl *dl) { struct cmd_dev_flash_status_ctx ctx = {.dl = dl,}; - struct mnlg_socket *nlg_ntf; + struct mnlu_gen_socket nlg_ntf; struct nlmsghdr *nlh; int pipe_r, pipe_w; int pipe_fds[2]; @@ -3736,7 +3692,7 @@ static int cmd_dev_flash(struct dl *dl) return 0; } - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_FLASH_UPDATE, + nlh = mnlu_gen_socket_cmd_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, @@ -3744,11 +3700,12 @@ static int cmd_dev_flash(struct dl *dl) if (err) return err; - nlg_ntf = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION); - if (!nlg_ntf) + err = mnlu_gen_socket_open(&nlg_ntf, DEVLINK_GENL_NAME, + DEVLINK_GENL_VERSION); + if (err) return err; - err = _mnlg_socket_group_add(nlg_ntf, DEVLINK_GENL_MCGRP_CONFIG_NAME); + err = _mnlg_socket_group_add(&nlg_ntf, DEVLINK_GENL_MCGRP_CONFIG_NAME); if (err) goto err_socket; @@ -3772,7 +3729,7 @@ static int cmd_dev_flash(struct dl *dl) int cc; close(pipe_r); - err = _mnlg_socket_send(dl->nlg, nlh); + err = _mnlg_socket_send(&dl->nlg, nlh); cc = write(pipe_w, &err, sizeof(err)); close(pipe_w); exit(cc != sizeof(err)); @@ -3785,16 +3742,17 @@ static int cmd_dev_flash(struct dl *dl) clock_gettime(CLOCK_MONOTONIC, &ctx.time_of_last_status); do { - err = cmd_dev_flash_fds_process(&ctx, nlg_ntf, pipe_r); + err = cmd_dev_flash_fds_process(&ctx, &nlg_ntf, pipe_r); if (err) goto out; } while (!ctx.flash_done || (ctx.not_first && !ctx.received_end)); - err = _mnlg_socket_recv_run(dl->nlg, NULL, NULL); + err = mnlu_gen_socket_recv_run(&dl->nlg, NULL, NULL); + out: close(pipe_r); err_socket: - mnlg_socket_close(nlg_ntf); + mnlu_gen_socket_close(&nlg_ntf); return err; } @@ -4039,7 +3997,7 @@ static int cmd_port_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0); @@ -4048,7 +4006,7 @@ static int cmd_port_show(struct dl *dl) } pr_out_section_start(dl, "port"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_show_cb, dl); pr_out_section_end(dl); return err; } @@ -4058,14 +4016,14 @@ static int cmd_port_set(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0); if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_port_split(struct dl *dl) @@ -4073,14 +4031,14 @@ static int cmd_port_split(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SPLIT, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0); if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_port_unsplit(struct dl *dl) @@ -4088,14 +4046,14 @@ static int cmd_port_unsplit(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_UNSPLIT, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0); if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_port_param_show(struct dl *dl) @@ -4107,7 +4065,8 @@ static int cmd_port_param_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_PARAM_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_GET, + flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | @@ -4117,7 +4076,7 @@ static int cmd_port_param_show(struct dl *dl) } pr_out_section_start(dl, "param"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_param_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_param_show_cb, dl); pr_out_section_end(dl); return err; @@ -4137,14 +4096,15 @@ static int cmd_port_function_set(struct dl *dl) cmd_port_function_help(); return 0; } - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET, NLM_F_REQUEST | NLM_F_ACK); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SET, + NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, DL_OPT_PORT_FUNCTION_HW_ADDR | DL_OPT_PORT_FUNCTION_STATE); if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_port_param_set_cb(const struct nlmsghdr *nlh, void *data) @@ -4234,17 +4194,17 @@ static int cmd_port_param_set(struct dl *dl) return err; /* Get value type */ - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_PARAM_GET, - NLM_F_REQUEST | NLM_F_ACK); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_GET, + NLM_F_REQUEST | NLM_F_ACK); dl_opts_put(nlh, dl); ctx.dl = dl; - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_param_set_cb, &ctx); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_param_set_cb, &ctx); if (err) return err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_PARAM_SET, - NLM_F_REQUEST | NLM_F_ACK); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_SET, + NLM_F_REQUEST | NLM_F_ACK); dl_opts_put(nlh, dl); conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN, @@ -4321,7 +4281,7 @@ static int cmd_port_param_set(struct dl *dl) printf("Value type not supported\n"); return -ENOTSUP; } - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); err_param_value_parse: pr_err("Value \"%s\" is not a number or not within range\n", @@ -4377,8 +4337,8 @@ static int cmd_port_add(struct dl *dl) return 0; } - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_NEW, - NLM_F_REQUEST | NLM_F_ACK); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_NEW, + NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_HANDLEP | DL_OPT_PORT_FLAVOUR | DL_OPT_PORT_PFNUMBER, @@ -4386,7 +4346,7 @@ static int cmd_port_add(struct dl *dl) if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_show_cb, dl); } static void cmd_port_del_help(void) @@ -4404,14 +4364,14 @@ static int cmd_port_del(struct dl *dl) return 0; } - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_DEL, - NLM_F_REQUEST | NLM_F_ACK); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_DEL, + NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0); if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_port(struct dl *dl) @@ -4525,7 +4485,7 @@ static int cmd_sb_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); @@ -4534,7 +4494,7 @@ static int cmd_sb_show(struct dl *dl) } pr_out_section_start(dl, "sb"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_show_cb, dl); pr_out_section_end(dl); return err; } @@ -4602,7 +4562,7 @@ static int cmd_sb_pool_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL, @@ -4612,7 +4572,7 @@ static int cmd_sb_pool_show(struct dl *dl) } pr_out_section_start(dl, "pool"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_pool_show_cb, dl); pr_out_section_end(dl); return err; } @@ -4622,7 +4582,7 @@ static int cmd_sb_pool_set(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_POOL_SET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL | @@ -4630,7 +4590,7 @@ static int cmd_sb_pool_set(struct dl *dl) if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_sb_pool(struct dl *dl) @@ -4687,7 +4647,7 @@ static int cmd_sb_port_pool_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, @@ -4698,7 +4658,7 @@ static int cmd_sb_port_pool_show(struct dl *dl) } pr_out_section_start(dl, "port_pool"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); pr_out_section_end(dl); return 0; } @@ -4708,7 +4668,7 @@ static int cmd_sb_port_pool_set(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL | @@ -4716,7 +4676,7 @@ static int cmd_sb_port_pool_set(struct dl *dl) if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_sb_port_pool(struct dl *dl) @@ -4791,7 +4751,7 @@ static int cmd_sb_tc_bind_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | @@ -4801,7 +4761,7 @@ static int cmd_sb_tc_bind_show(struct dl *dl) } pr_out_section_start(dl, "tc_bind"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); pr_out_section_end(dl); return err; } @@ -4811,7 +4771,7 @@ static int cmd_sb_tc_bind_set(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | @@ -4820,7 +4780,7 @@ static int cmd_sb_tc_bind_set(struct dl *dl) if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_sb_tc_bind(struct dl *dl) @@ -5137,16 +5097,16 @@ static int cmd_sb_occ_show(struct dl *dl) if (!occ_show) return -ENOMEM; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_occ_port_pool_process_cb, occ_show); if (err) goto out; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_occ_tc_pool_process_cb, occ_show); if (err) goto out; @@ -5165,14 +5125,14 @@ static int cmd_sb_occ_snapshot(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_sb_occ_clearmax(struct dl *dl) @@ -5180,14 +5140,14 @@ static int cmd_sb_occ_clearmax(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_sb_occ(struct dl *dl) @@ -5544,12 +5504,12 @@ static int cmd_mon_show(struct dl *dl) return -EINVAL; } } - err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME); + err = _mnlg_socket_group_add(&dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME); if (err) return err; open_json_object(NULL); open_json_array(PRINT_JSON, "mon"); - err = _mnlg_socket_recv_run_intr(dl->nlg, cmd_mon_show_cb, dl); + err = _mnlg_socket_recv_run_intr(&dl->nlg, cmd_mon_show_cb, dl); close_json_array(PRINT_JSON, NULL); close_json_object(); if (err) @@ -6065,7 +6025,7 @@ static int cmd_dpipe_headers_show(struct dl *dl) uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0); if (err) @@ -6078,7 +6038,7 @@ static int cmd_dpipe_headers_show(struct dl *dl) ctx.print_headers = true; pr_out_section_start(dl, "header"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_header_cb, &ctx); if (err) pr_err("error get headers %s\n", strerror(ctx.err)); pr_out_section_end(dl); @@ -6467,7 +6427,7 @@ static int cmd_dpipe_table_show(struct dl *dl) if (err) return err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags); err = dpipe_ctx_init(&dpipe_ctx, dl); if (err) @@ -6476,7 +6436,7 @@ static int cmd_dpipe_table_show(struct dl *dl) dpipe_ctx.print_tables = true; dl_opts_put(nlh, dl); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_header_cb, &dpipe_ctx); if (err) { pr_err("error get headers %s\n", strerror(dpipe_ctx.err)); @@ -6488,19 +6448,19 @@ static int cmd_dpipe_table_show(struct dl *dl) goto err_resource_ctx_init; resource_ctx.print_resources = false; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, flags); dl_opts_put(nlh, dl); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb, + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_resource_dump_cb, &resource_ctx); if (!err) dpipe_ctx.resources = resource_ctx.resources; flags = NLM_F_REQUEST | NLM_F_ACK; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags); dl_opts_put(nlh, dl); pr_out_section_start(dl, "table"); - _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, &dpipe_ctx); + mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_table_show_cb, &dpipe_ctx); pr_out_section_end(dl); resource_ctx_fini(&resource_ctx); @@ -6518,7 +6478,7 @@ static int cmd_dpipe_table_set(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, @@ -6527,7 +6487,7 @@ static int cmd_dpipe_table_set(struct dl *dl) if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } enum dpipe_value_type { @@ -6895,20 +6855,20 @@ static int cmd_dpipe_table_dump(struct dl *dl) if (err) goto out; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags); dl_opts_put(nlh, dl); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_header_cb, &ctx); if (err) { pr_err("error get headers %s\n", strerror(ctx.err)); goto out; } flags = NLM_F_REQUEST | NLM_F_ACK; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags); dl_opts_put(nlh, dl); pr_out_section_start(dl, "table_entry"); - _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, &ctx); + mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, &ctx); pr_out_section_end(dl); out: dpipe_ctx_fini(&ctx); @@ -7172,7 +7132,7 @@ static int cmd_resource_show(struct dl *dl) if (err) return err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, NLM_F_REQUEST); dl_opts_put(nlh, dl); @@ -7180,7 +7140,7 @@ static int cmd_resource_show(struct dl *dl) if (err) return err; - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_table_show_cb, &dpipe_ctx); if (err) { pr_err("error get tables %s\n", strerror(dpipe_ctx.err)); @@ -7193,11 +7153,11 @@ static int cmd_resource_show(struct dl *dl) resource_ctx.print_resources = true; resource_ctx.tables = dpipe_ctx.tables; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, NLM_F_REQUEST | NLM_F_ACK); dl_opts_put(nlh, dl); pr_out_section_start(dl, "resources"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb, + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_resource_dump_cb, &resource_ctx); pr_out_section_end(dl); resource_ctx_fini(&resource_ctx); @@ -7273,10 +7233,10 @@ static int cmd_resource_set(struct dl *dl) if (err) goto out; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, NLM_F_REQUEST); dl_opts_put(nlh, dl); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb, &ctx); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_resource_dump_cb, &ctx); if (err) { pr_err("error getting resources %s\n", strerror(ctx.err)); goto out; @@ -7290,11 +7250,11 @@ static int cmd_resource_set(struct dl *dl) goto out; } - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RESOURCE_SET, NLM_F_REQUEST | NLM_F_ACK); dl_opts_put(nlh, dl); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); out: resource_ctx_fini(&ctx); return err; @@ -7435,7 +7395,7 @@ static int cmd_region_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION, 0); @@ -7444,7 +7404,7 @@ static int cmd_region_show(struct dl *dl) } pr_out_section_start(dl, "regions"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_region_show_cb, dl); pr_out_section_end(dl); return err; } @@ -7454,7 +7414,7 @@ static int cmd_region_snapshot_del(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_DEL, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_DEL, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION | @@ -7462,7 +7422,7 @@ static int cmd_region_snapshot_del(struct dl *dl) if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_region_read_cb(const struct nlmsghdr *nlh, void *data) @@ -7504,7 +7464,7 @@ static int cmd_region_dump(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_READ, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION | @@ -7513,7 +7473,7 @@ static int cmd_region_dump(struct dl *dl) return err; pr_out_section_start(dl, "dump"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_region_read_cb, dl); pr_out_section_end(dl); if (!dl->json_output) pr_out("\n"); @@ -7525,7 +7485,7 @@ static int cmd_region_read(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_READ, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION | @@ -7535,7 +7495,7 @@ static int cmd_region_read(struct dl *dl) return err; pr_out_section_start(dl, "read"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_region_read_cb, dl); pr_out_section_end(dl); if (!dl->json_output) pr_out("\n"); @@ -7564,7 +7524,7 @@ static int cmd_region_snapshot_new(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_NEW, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_NEW, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION, @@ -7573,7 +7533,7 @@ static int cmd_region_snapshot_new(struct dl *dl) return err; pr_out_section_start(dl, "regions"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_snapshot_new_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_region_snapshot_new_cb, dl); pr_out_section_end(dl); return err; } @@ -7619,7 +7579,7 @@ 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, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_SET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP | DL_OPT_HEALTH_REPORTER_NAME, DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD | @@ -7629,7 +7589,7 @@ static int cmd_health_set_params(struct dl *dl) return err; dl_opts_put(nlh, dl); - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_health_dump_clear(struct dl *dl) @@ -7637,7 +7597,7 @@ 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, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, @@ -7647,7 +7607,7 @@ static int cmd_health_dump_clear(struct dl *dl) return err; dl_opts_put(nlh, dl); - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data) @@ -7886,7 +7846,7 @@ static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, cmd, flags | NLM_F_REQUEST | NLM_F_ACK); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, cmd, flags | NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_HANDLEP | @@ -7895,7 +7855,7 @@ static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags) return err; cmd_fmsg_init(dl, &data); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_fmsg_object_cb, &data); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_fmsg_object_cb, &data); free(data.name); return err; } @@ -7926,7 +7886,7 @@ static int cmd_health_recover(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_RECOVER, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_RECOVER, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, @@ -7936,7 +7896,7 @@ static int cmd_health_recover(struct dl *dl) return err; dl_opts_put(nlh, dl); - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } enum devlink_health_reporter_state { @@ -8102,7 +8062,7 @@ static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_GET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_GET, flags); if (dl_argc(dl) > 0) { @@ -8115,7 +8075,7 @@ static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port) } pr_out_section_start(dl, "health"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_health_show_cb, &ctx); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_health_show_cb, &ctx); pr_out_section_end(dl); return err; } @@ -8284,7 +8244,7 @@ static int cmd_trap_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, @@ -8294,7 +8254,7 @@ static int cmd_trap_show(struct dl *dl) } pr_out_section_start(dl, "trap"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_trap_show_cb, dl); pr_out_section_end(dl); return err; @@ -8305,7 +8265,7 @@ static int cmd_trap_set(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_SET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_TRAP_NAME, @@ -8313,7 +8273,7 @@ static int cmd_trap_set(struct dl *dl) if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array) @@ -8359,7 +8319,7 @@ static int cmd_trap_group_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_GROUP_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, @@ -8370,7 +8330,7 @@ static int cmd_trap_group_show(struct dl *dl) } pr_out_section_start(dl, "trap_group"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_group_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_trap_group_show_cb, dl); pr_out_section_end(dl); return err; @@ -8381,7 +8341,7 @@ static int cmd_trap_group_set(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_GROUP_SET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, @@ -8390,7 +8350,7 @@ static int cmd_trap_group_set(struct dl *dl) if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_trap_group(struct dl *dl) @@ -8456,7 +8416,7 @@ static int cmd_trap_policer_show(struct dl *dl) if (dl_argc(dl) == 0) flags |= NLM_F_DUMP; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_POLICER_GET, flags); + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_POLICER_GET, flags); if (dl_argc(dl) > 0) { err = dl_argv_parse_put(nlh, dl, @@ -8467,7 +8427,7 @@ static int cmd_trap_policer_show(struct dl *dl) } pr_out_section_start(dl, "trap_policer"); - err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_policer_show_cb, dl); + err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_trap_policer_show_cb, dl); pr_out_section_end(dl); return err; @@ -8478,7 +8438,7 @@ static int cmd_trap_policer_set(struct dl *dl) struct nlmsghdr *nlh; int err; - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_POLICER_SET, + nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_POLICER_SET, NLM_F_REQUEST | NLM_F_ACK); err = dl_argv_parse_put(nlh, dl, @@ -8488,7 +8448,7 @@ static int cmd_trap_policer_set(struct dl *dl) if (err) return err; - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); + return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL); } static int cmd_trap_policer(struct dl *dl) @@ -8583,8 +8543,9 @@ static int dl_init(struct dl *dl) { int err; - dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION); - if (!dl->nlg) { + err = mnlu_gen_socket_open(&dl->nlg, DEVLINK_GENL_NAME, + DEVLINK_GENL_VERSION); + if (err) { pr_err("Failed to connect to devlink Netlink\n"); return -errno; } @@ -8598,7 +8559,7 @@ static int dl_init(struct dl *dl) return 0; err_ifname_map_create: - mnlg_socket_close(dl->nlg); + mnlu_gen_socket_close(&dl->nlg); return err; } @@ -8606,7 +8567,7 @@ static void dl_fini(struct dl *dl) { delete_json_obj_plain(); ifname_map_fini(dl); - mnlg_socket_close(dl->nlg); + mnlu_gen_socket_close(&dl->nlg); } static struct dl *dl_alloc(void) diff --git a/devlink/mnlg.c b/devlink/mnlg.c index 21b10c5a..e6d92742 100644 --- a/devlink/mnlg.c +++ b/devlink/mnlg.c @@ -30,38 +30,11 @@ struct mnlg_socket { unsigned int seq; }; -static struct nlmsghdr *__mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd, - uint16_t flags, uint32_t id, - uint8_t version) -{ - struct genlmsghdr genl = { - .cmd = cmd, - .version = version, - }; - struct nlmsghdr *nlh; - - nlh = mnlu_msg_prepare(nlg->buf, id, flags, &genl, sizeof(genl)); - nlg->seq = nlh->nlmsg_seq; - return nlh; -} - -struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd, - uint16_t flags) -{ - return __mnlg_msg_prepare(nlg, cmd, flags, nlg->id, nlg->version); -} - -int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh) +int mnlg_socket_send(struct mnlu_gen_socket *nlg, const struct nlmsghdr *nlh) { return mnl_socket_sendto(nlg->nl, nlh, nlh->nlmsg_len); } -int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data) -{ - return mnlu_socket_recv_run(nlg->nl, nlg->seq, nlg->buf, MNL_SOCKET_BUFFER_SIZE, - data_cb, data); -} - struct group_info { bool found; uint32_t id; @@ -141,15 +114,17 @@ static int get_group_id_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } -int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name) +int mnlg_socket_group_add(struct mnlu_gen_socket *nlg, const char *group_name) { struct nlmsghdr *nlh; struct group_info group_info; int err; - nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY, - NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1); - mnl_attr_put_u16(nlh, CTRL_ATTR_FAMILY_ID, nlg->id); + nlh = _mnlu_gen_socket_cmd_prepare(nlg, CTRL_CMD_GETFAMILY, + NLM_F_REQUEST | NLM_F_ACK, + GENL_ID_CTRL, 1); + + mnl_attr_put_u16(nlh, CTRL_ATTR_FAMILY_ID, nlg->family); err = mnlg_socket_send(nlg, nlh); if (err < 0) @@ -157,7 +132,7 @@ int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name) group_info.found = false; group_info.name = group_name; - err = mnlg_socket_recv_run(nlg, get_group_id_cb, &group_info); + err = mnlu_gen_socket_recv_run(nlg, get_group_id_cb, &group_info); if (err < 0) return err; @@ -174,85 +149,7 @@ int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name) return 0; } -static int get_family_id_attr_cb(const struct nlattr *attr, void *data) -{ - const struct nlattr **tb = data; - int type = mnl_attr_get_type(attr); - - if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0) - return MNL_CB_ERROR; - - if (type == CTRL_ATTR_FAMILY_ID && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - tb[type] = attr; - return MNL_CB_OK; -} - -static int get_family_id_cb(const struct nlmsghdr *nlh, void *data) -{ - uint32_t *p_id = data; - struct nlattr *tb[CTRL_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), get_family_id_attr_cb, tb); - if (!tb[CTRL_ATTR_FAMILY_ID]) - return MNL_CB_ERROR; - *p_id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]); - return MNL_CB_OK; -} - -struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version) -{ - struct mnlg_socket *nlg; - struct nlmsghdr *nlh; - int err; - - nlg = malloc(sizeof(*nlg)); - if (!nlg) - return NULL; - - nlg->buf = malloc(MNL_SOCKET_BUFFER_SIZE); - if (!nlg->buf) - goto err_buf_alloc; - - nlg->nl = mnlu_socket_open(NETLINK_GENERIC); - if (!nlg->nl) - goto err_socket_open; - - nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY, - NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1); - mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name); - - err = mnlg_socket_send(nlg, nlh); - if (err < 0) - goto err_mnlg_socket_send; - - err = mnlg_socket_recv_run(nlg, get_family_id_cb, &nlg->id); - if (err < 0) - goto err_mnlg_socket_recv_run; - - nlg->version = version; - return nlg; - -err_mnlg_socket_recv_run: -err_mnlg_socket_send: - mnl_socket_close(nlg->nl); -err_socket_open: - free(nlg->buf); -err_buf_alloc: - free(nlg); - return NULL; -} - -void mnlg_socket_close(struct mnlg_socket *nlg) -{ - mnl_socket_close(nlg->nl); - free(nlg->buf); - free(nlg); -} - -int mnlg_socket_get_fd(struct mnlg_socket *nlg) +int mnlg_socket_get_fd(struct mnlu_gen_socket *nlg) { return mnl_socket_get_fd(nlg->nl); } diff --git a/devlink/mnlg.h b/devlink/mnlg.h index 61bc5a3f..24aa1756 100644 --- a/devlink/mnlg.h +++ b/devlink/mnlg.h @@ -14,15 +14,10 @@ #include -struct mnlg_socket; +struct mnlu_gen_socket; -struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd, - uint16_t flags); -int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh); -int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data); -int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name); -struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version); -void mnlg_socket_close(struct mnlg_socket *nlg); -int mnlg_socket_get_fd(struct mnlg_socket *nlg); +int mnlg_socket_send(struct mnlu_gen_socket *nlg, const struct nlmsghdr *nlh); +int mnlg_socket_group_add(struct mnlu_gen_socket *nlg, const char *group_name); +int mnlg_socket_get_fd(struct mnlu_gen_socket *nlg); #endif /* _MNLG_H_ */ diff --git a/etc/iproute2/rt_protos b/etc/iproute2/rt_protos index 7cafddc1..0f98609f 100644 --- a/etc/iproute2/rt_protos +++ b/etc/iproute2/rt_protos @@ -17,6 +17,7 @@ 16 dhcp 18 keepalived 42 babel +99 openr 186 bgp 187 isis 188 ospf diff --git a/include/json_print.h b/include/json_print.h index 6fcf9fd9..91b34571 100644 --- a/include/json_print.h +++ b/include/json_print.h @@ -81,6 +81,7 @@ _PRINT_FUNC(0xhex, unsigned long long) _PRINT_FUNC(luint, unsigned long) _PRINT_FUNC(lluint, unsigned long long) _PRINT_FUNC(float, double) +_PRINT_FUNC(tv, const struct timeval *) #undef _PRINT_FUNC #define _PRINT_NAME_VALUE_FUNC(type_name, type, format_char) \ diff --git a/include/libgenl.h b/include/libgenl.h index 656493a2..97281cc1 100644 --- a/include/libgenl.h +++ b/include/libgenl.h @@ -21,6 +21,7 @@ struct { \ }, \ } +int genl_add_mcast_grp(struct rtnl_handle *grth, __u16 genl_family, const char *group); int genl_resolve_family(struct rtnl_handle *grth, const char *family); int genl_init_handle(struct rtnl_handle *grth, const char *family, int *genl_family); diff --git a/include/libnetlink.h b/include/libnetlink.h index b9073a6a..6bff6bae 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -69,6 +69,8 @@ int rtnl_neightbldump_req(struct rtnl_handle *rth, int family) __attribute__((warn_unused_result)); int rtnl_mdbdump_req(struct rtnl_handle *rth, int family) __attribute__((warn_unused_result)); +int rtnl_brvlandump_req(struct rtnl_handle *rth, int family, __u32 dump_flags) + __attribute__((warn_unused_result)); int rtnl_netconfdump_req(struct rtnl_handle *rth, int family) __attribute__((warn_unused_result)); @@ -97,6 +99,9 @@ int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n) int rtnl_nexthopdump_req(struct rtnl_handle *rth, int family, req_filter_fn_t filter_fn) __attribute__((warn_unused_result)); +int rtnl_nexthop_bucket_dump_req(struct rtnl_handle *rth, int family, + req_filter_fn_t filter_fn) + __attribute__((warn_unused_result)); struct rtnl_ctrl_data { int nsid; @@ -280,6 +285,11 @@ int rtnl_from_file(FILE *, rtnl_listen_filter_t handler, ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct if_stats_msg)))) #endif +#ifndef BRVLAN_RTA +#define BRVLAN_RTA(r) \ + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct br_vlan_msg)))) +#endif + /* User defined nlmsg_type which is used mostly for logging netlink * messages from dump file */ #define NLMSG_TSTAMP 15 diff --git a/include/mnl_utils.h b/include/mnl_utils.h index 9e7d6879..aa5f0a9b 100644 --- a/include/mnl_utils.h +++ b/include/mnl_utils.h @@ -13,6 +13,10 @@ struct mnlu_gen_socket { int mnlu_gen_socket_open(struct mnlu_gen_socket *nlg, const char *family_name, uint8_t version); void mnlu_gen_socket_close(struct mnlu_gen_socket *nlg); +struct nlmsghdr * +_mnlu_gen_socket_cmd_prepare(struct mnlu_gen_socket *nlg, + uint8_t cmd, uint16_t flags, + uint32_t id, uint8_t version); struct nlmsghdr *mnlu_gen_socket_cmd_prepare(struct mnlu_gen_socket *nlg, uint8_t cmd, uint16_t flags); int mnlu_gen_socket_sndrcv(struct mnlu_gen_socket *nlg, const struct nlmsghdr *nlh, @@ -23,5 +27,7 @@ struct nlmsghdr *mnlu_msg_prepare(void *buf, uint32_t nlmsg_type, uint16_t flags void *extra_header, size_t extra_header_size); int mnlu_socket_recv_run(struct mnl_socket *nl, unsigned int seq, void *buf, size_t buf_size, mnl_cb_t cb, void *data); +int mnlu_gen_socket_recv_run(struct mnlu_gen_socket *nlg, mnl_cb_t cb, + void *data); #endif /* __MNL_UTILS_H__ */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index b1aba6af..793655ed 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -93,7 +93,717 @@ union bpf_iter_link_info { } map; }; -/* BPF syscall commands, see bpf(2) man-page for details. */ +/* BPF syscall commands, see bpf(2) man-page for more details. */ +/** + * DOC: eBPF Syscall Preamble + * + * The operation to be performed by the **bpf**\ () system call is determined + * by the *cmd* argument. Each operation takes an accompanying argument, + * provided via *attr*, which is a pointer to a union of type *bpf_attr* (see + * below). The size argument is the size of the union pointed to by *attr*. + */ +/** + * DOC: eBPF Syscall Commands + * + * BPF_MAP_CREATE + * Description + * Create a map and return a file descriptor that refers to the + * map. The close-on-exec file descriptor flag (see **fcntl**\ (2)) + * is automatically enabled for the new file descriptor. + * + * Applying **close**\ (2) to the file descriptor returned by + * **BPF_MAP_CREATE** will delete the map (but see NOTES). + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_MAP_LOOKUP_ELEM + * Description + * Look up an element with a given *key* in the map referred to + * by the file descriptor *map_fd*. + * + * The *flags* argument may be specified as one of the + * following: + * + * **BPF_F_LOCK** + * Look up the value of a spin-locked map without + * returning the lock. This must be specified if the + * elements contain a spinlock. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_MAP_UPDATE_ELEM + * Description + * Create or update an element (key/value pair) in a specified map. + * + * The *flags* argument should be specified as one of the + * following: + * + * **BPF_ANY** + * Create a new element or update an existing element. + * **BPF_NOEXIST** + * Create a new element only if it did not exist. + * **BPF_EXIST** + * Update an existing element. + * **BPF_F_LOCK** + * Update a spin_lock-ed map element. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * May set *errno* to **EINVAL**, **EPERM**, **ENOMEM**, + * **E2BIG**, **EEXIST**, or **ENOENT**. + * + * **E2BIG** + * The number of elements in the map reached the + * *max_entries* limit specified at map creation time. + * **EEXIST** + * If *flags* specifies **BPF_NOEXIST** and the element + * with *key* already exists in the map. + * **ENOENT** + * If *flags* specifies **BPF_EXIST** and the element with + * *key* does not exist in the map. + * + * BPF_MAP_DELETE_ELEM + * Description + * Look up and delete an element by key in a specified map. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_MAP_GET_NEXT_KEY + * Description + * Look up an element by key in a specified map and return the key + * of the next element. Can be used to iterate over all elements + * in the map. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * The following cases can be used to iterate over all elements of + * the map: + * + * * If *key* is not found, the operation returns zero and sets + * the *next_key* pointer to the key of the first element. + * * If *key* is found, the operation returns zero and sets the + * *next_key* pointer to the key of the next element. + * * If *key* is the last element, returns -1 and *errno* is set + * to **ENOENT**. + * + * May set *errno* to **ENOMEM**, **EFAULT**, **EPERM**, or + * **EINVAL** on error. + * + * BPF_PROG_LOAD + * Description + * Verify and load an eBPF program, returning a new file + * descriptor associated with the program. + * + * Applying **close**\ (2) to the file descriptor returned by + * **BPF_PROG_LOAD** will unload the eBPF program (but see NOTES). + * + * The close-on-exec file descriptor flag (see **fcntl**\ (2)) is + * automatically enabled for the new file descriptor. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_OBJ_PIN + * Description + * Pin an eBPF program or map referred by the specified *bpf_fd* + * to the provided *pathname* on the filesystem. + * + * The *pathname* argument must not contain a dot ("."). + * + * On success, *pathname* retains a reference to the eBPF object, + * preventing deallocation of the object when the original + * *bpf_fd* is closed. This allow the eBPF object to live beyond + * **close**\ (\ *bpf_fd*\ ), and hence the lifetime of the parent + * process. + * + * Applying **unlink**\ (2) or similar calls to the *pathname* + * unpins the object from the filesystem, removing the reference. + * If no other file descriptors or filesystem nodes refer to the + * same object, it will be deallocated (see NOTES). + * + * The filesystem type for the parent directory of *pathname* must + * be **BPF_FS_MAGIC**. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_OBJ_GET + * Description + * Open a file descriptor for the eBPF object pinned to the + * specified *pathname*. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_PROG_ATTACH + * Description + * Attach an eBPF program to a *target_fd* at the specified + * *attach_type* hook. + * + * The *attach_type* specifies the eBPF attachment point to + * attach the program to, and must be one of *bpf_attach_type* + * (see below). + * + * The *attach_bpf_fd* must be a valid file descriptor for a + * loaded eBPF program of a cgroup, flow dissector, LIRC, sockmap + * or sock_ops type corresponding to the specified *attach_type*. + * + * The *target_fd* must be a valid file descriptor for a kernel + * object which depends on the attach type of *attach_bpf_fd*: + * + * **BPF_PROG_TYPE_CGROUP_DEVICE**, + * **BPF_PROG_TYPE_CGROUP_SKB**, + * **BPF_PROG_TYPE_CGROUP_SOCK**, + * **BPF_PROG_TYPE_CGROUP_SOCK_ADDR**, + * **BPF_PROG_TYPE_CGROUP_SOCKOPT**, + * **BPF_PROG_TYPE_CGROUP_SYSCTL**, + * **BPF_PROG_TYPE_SOCK_OPS** + * + * Control Group v2 hierarchy with the eBPF controller + * enabled. Requires the kernel to be compiled with + * **CONFIG_CGROUP_BPF**. + * + * **BPF_PROG_TYPE_FLOW_DISSECTOR** + * + * Network namespace (eg /proc/self/ns/net). + * + * **BPF_PROG_TYPE_LIRC_MODE2** + * + * LIRC device path (eg /dev/lircN). Requires the kernel + * to be compiled with **CONFIG_BPF_LIRC_MODE2**. + * + * **BPF_PROG_TYPE_SK_SKB**, + * **BPF_PROG_TYPE_SK_MSG** + * + * eBPF map of socket type (eg **BPF_MAP_TYPE_SOCKHASH**). + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_PROG_DETACH + * Description + * Detach the eBPF program associated with the *target_fd* at the + * hook specified by *attach_type*. The program must have been + * previously attached using **BPF_PROG_ATTACH**. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_PROG_TEST_RUN + * Description + * Run the eBPF program associated with the *prog_fd* a *repeat* + * number of times against a provided program context *ctx_in* and + * data *data_in*, and return the modified program context + * *ctx_out*, *data_out* (for example, packet data), result of the + * execution *retval*, and *duration* of the test run. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * **ENOSPC** + * Either *data_size_out* or *ctx_size_out* is too small. + * **ENOTSUPP** + * This command is not supported by the program type of + * the program referred to by *prog_fd*. + * + * BPF_PROG_GET_NEXT_ID + * Description + * Fetch the next eBPF program currently loaded into the kernel. + * + * Looks for the eBPF program with an id greater than *start_id* + * and updates *next_id* on success. If no other eBPF programs + * remain with ids higher than *start_id*, returns -1 and sets + * *errno* to **ENOENT**. + * + * Return + * Returns zero on success. On error, or when no id remains, -1 + * is returned and *errno* is set appropriately. + * + * BPF_MAP_GET_NEXT_ID + * Description + * Fetch the next eBPF map currently loaded into the kernel. + * + * Looks for the eBPF map with an id greater than *start_id* + * and updates *next_id* on success. If no other eBPF maps + * remain with ids higher than *start_id*, returns -1 and sets + * *errno* to **ENOENT**. + * + * Return + * Returns zero on success. On error, or when no id remains, -1 + * is returned and *errno* is set appropriately. + * + * BPF_PROG_GET_FD_BY_ID + * Description + * Open a file descriptor for the eBPF program corresponding to + * *prog_id*. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_MAP_GET_FD_BY_ID + * Description + * Open a file descriptor for the eBPF map corresponding to + * *map_id*. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_OBJ_GET_INFO_BY_FD + * Description + * Obtain information about the eBPF object corresponding to + * *bpf_fd*. + * + * Populates up to *info_len* bytes of *info*, which will be in + * one of the following formats depending on the eBPF object type + * of *bpf_fd*: + * + * * **struct bpf_prog_info** + * * **struct bpf_map_info** + * * **struct bpf_btf_info** + * * **struct bpf_link_info** + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_PROG_QUERY + * Description + * Obtain information about eBPF programs associated with the + * specified *attach_type* hook. + * + * The *target_fd* must be a valid file descriptor for a kernel + * object which depends on the attach type of *attach_bpf_fd*: + * + * **BPF_PROG_TYPE_CGROUP_DEVICE**, + * **BPF_PROG_TYPE_CGROUP_SKB**, + * **BPF_PROG_TYPE_CGROUP_SOCK**, + * **BPF_PROG_TYPE_CGROUP_SOCK_ADDR**, + * **BPF_PROG_TYPE_CGROUP_SOCKOPT**, + * **BPF_PROG_TYPE_CGROUP_SYSCTL**, + * **BPF_PROG_TYPE_SOCK_OPS** + * + * Control Group v2 hierarchy with the eBPF controller + * enabled. Requires the kernel to be compiled with + * **CONFIG_CGROUP_BPF**. + * + * **BPF_PROG_TYPE_FLOW_DISSECTOR** + * + * Network namespace (eg /proc/self/ns/net). + * + * **BPF_PROG_TYPE_LIRC_MODE2** + * + * LIRC device path (eg /dev/lircN). Requires the kernel + * to be compiled with **CONFIG_BPF_LIRC_MODE2**. + * + * **BPF_PROG_QUERY** always fetches the number of programs + * attached and the *attach_flags* which were used to attach those + * programs. Additionally, if *prog_ids* is nonzero and the number + * of attached programs is less than *prog_cnt*, populates + * *prog_ids* with the eBPF program ids of the programs attached + * at *target_fd*. + * + * The following flags may alter the result: + * + * **BPF_F_QUERY_EFFECTIVE** + * Only return information regarding programs which are + * currently effective at the specified *target_fd*. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_RAW_TRACEPOINT_OPEN + * Description + * Attach an eBPF program to a tracepoint *name* to access kernel + * internal arguments of the tracepoint in their raw form. + * + * The *prog_fd* must be a valid file descriptor associated with + * a loaded eBPF program of type **BPF_PROG_TYPE_RAW_TRACEPOINT**. + * + * No ABI guarantees are made about the content of tracepoint + * arguments exposed to the corresponding eBPF program. + * + * Applying **close**\ (2) to the file descriptor returned by + * **BPF_RAW_TRACEPOINT_OPEN** will delete the map (but see NOTES). + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_BTF_LOAD + * Description + * Verify and load BPF Type Format (BTF) metadata into the kernel, + * returning a new file descriptor associated with the metadata. + * BTF is described in more detail at + * https://www.kernel.org/doc/html/latest/bpf/btf.html. + * + * The *btf* parameter must point to valid memory providing + * *btf_size* bytes of BTF binary metadata. + * + * The returned file descriptor can be passed to other **bpf**\ () + * subcommands such as **BPF_PROG_LOAD** or **BPF_MAP_CREATE** to + * associate the BTF with those objects. + * + * Similar to **BPF_PROG_LOAD**, **BPF_BTF_LOAD** has optional + * parameters to specify a *btf_log_buf*, *btf_log_size* and + * *btf_log_level* which allow the kernel to return freeform log + * output regarding the BTF verification process. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_BTF_GET_FD_BY_ID + * Description + * Open a file descriptor for the BPF Type Format (BTF) + * corresponding to *btf_id*. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_TASK_FD_QUERY + * Description + * Obtain information about eBPF programs associated with the + * target process identified by *pid* and *fd*. + * + * If the *pid* and *fd* are associated with a tracepoint, kprobe + * or uprobe perf event, then the *prog_id* and *fd_type* will + * be populated with the eBPF program id and file descriptor type + * of type **bpf_task_fd_type**. If associated with a kprobe or + * uprobe, the *probe_offset* and *probe_addr* will also be + * populated. Optionally, if *buf* is provided, then up to + * *buf_len* bytes of *buf* will be populated with the name of + * the tracepoint, kprobe or uprobe. + * + * The resulting *prog_id* may be introspected in deeper detail + * using **BPF_PROG_GET_FD_BY_ID** and **BPF_OBJ_GET_INFO_BY_FD**. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_MAP_LOOKUP_AND_DELETE_ELEM + * Description + * Look up an element with the given *key* in the map referred to + * by the file descriptor *fd*, and if found, delete the element. + * + * The **BPF_MAP_TYPE_QUEUE** and **BPF_MAP_TYPE_STACK** map types + * implement this command as a "pop" operation, deleting the top + * element rather than one corresponding to *key*. + * The *key* and *key_len* parameters should be zeroed when + * issuing this operation for these map types. + * + * This command is only valid for the following map types: + * * **BPF_MAP_TYPE_QUEUE** + * * **BPF_MAP_TYPE_STACK** + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_MAP_FREEZE + * Description + * Freeze the permissions of the specified map. + * + * Write permissions may be frozen by passing zero *flags*. + * Upon success, no future syscall invocations may alter the + * map state of *map_fd*. Write operations from eBPF programs + * are still possible for a frozen map. + * + * Not supported for maps of type **BPF_MAP_TYPE_STRUCT_OPS**. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_BTF_GET_NEXT_ID + * Description + * Fetch the next BPF Type Format (BTF) object currently loaded + * into the kernel. + * + * Looks for the BTF object with an id greater than *start_id* + * and updates *next_id* on success. If no other BTF objects + * remain with ids higher than *start_id*, returns -1 and sets + * *errno* to **ENOENT**. + * + * Return + * Returns zero on success. On error, or when no id remains, -1 + * is returned and *errno* is set appropriately. + * + * BPF_MAP_LOOKUP_BATCH + * Description + * Iterate and fetch multiple elements in a map. + * + * Two opaque values are used to manage batch operations, + * *in_batch* and *out_batch*. Initially, *in_batch* must be set + * to NULL to begin the batched operation. After each subsequent + * **BPF_MAP_LOOKUP_BATCH**, the caller should pass the resultant + * *out_batch* as the *in_batch* for the next operation to + * continue iteration from the current point. + * + * The *keys* and *values* are output parameters which must point + * to memory large enough to hold *count* items based on the key + * and value size of the map *map_fd*. The *keys* buffer must be + * of *key_size* * *count*. The *values* buffer must be of + * *value_size* * *count*. + * + * The *elem_flags* argument may be specified as one of the + * following: + * + * **BPF_F_LOCK** + * Look up the value of a spin-locked map without + * returning the lock. This must be specified if the + * elements contain a spinlock. + * + * On success, *count* elements from the map are copied into the + * user buffer, with the keys copied into *keys* and the values + * copied into the corresponding indices in *values*. + * + * If an error is returned and *errno* is not **EFAULT**, *count* + * is set to the number of successfully processed elements. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * May set *errno* to **ENOSPC** to indicate that *keys* or + * *values* is too small to dump an entire bucket during + * iteration of a hash-based map type. + * + * BPF_MAP_LOOKUP_AND_DELETE_BATCH + * Description + * Iterate and delete all elements in a map. + * + * This operation has the same behavior as + * **BPF_MAP_LOOKUP_BATCH** with two exceptions: + * + * * Every element that is successfully returned is also deleted + * from the map. This is at least *count* elements. Note that + * *count* is both an input and an output parameter. + * * Upon returning with *errno* set to **EFAULT**, up to + * *count* elements may be deleted without returning the keys + * and values of the deleted elements. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_MAP_UPDATE_BATCH + * Description + * Update multiple elements in a map by *key*. + * + * The *keys* and *values* are input parameters which must point + * to memory large enough to hold *count* items based on the key + * and value size of the map *map_fd*. The *keys* buffer must be + * of *key_size* * *count*. The *values* buffer must be of + * *value_size* * *count*. + * + * Each element specified in *keys* is sequentially updated to the + * value in the corresponding index in *values*. The *in_batch* + * and *out_batch* parameters are ignored and should be zeroed. + * + * The *elem_flags* argument should be specified as one of the + * following: + * + * **BPF_ANY** + * Create new elements or update a existing elements. + * **BPF_NOEXIST** + * Create new elements only if they do not exist. + * **BPF_EXIST** + * Update existing elements. + * **BPF_F_LOCK** + * Update spin_lock-ed map elements. This must be + * specified if the map value contains a spinlock. + * + * On success, *count* elements from the map are updated. + * + * If an error is returned and *errno* is not **EFAULT**, *count* + * is set to the number of successfully processed elements. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * May set *errno* to **EINVAL**, **EPERM**, **ENOMEM**, or + * **E2BIG**. **E2BIG** indicates that the number of elements in + * the map reached the *max_entries* limit specified at map + * creation time. + * + * May set *errno* to one of the following error codes under + * specific circumstances: + * + * **EEXIST** + * If *flags* specifies **BPF_NOEXIST** and the element + * with *key* already exists in the map. + * **ENOENT** + * If *flags* specifies **BPF_EXIST** and the element with + * *key* does not exist in the map. + * + * BPF_MAP_DELETE_BATCH + * Description + * Delete multiple elements in a map by *key*. + * + * The *keys* parameter is an input parameter which must point + * to memory large enough to hold *count* items based on the key + * size of the map *map_fd*, that is, *key_size* * *count*. + * + * Each element specified in *keys* is sequentially deleted. The + * *in_batch*, *out_batch*, and *values* parameters are ignored + * and should be zeroed. + * + * The *elem_flags* argument may be specified as one of the + * following: + * + * **BPF_F_LOCK** + * Look up the value of a spin-locked map without + * returning the lock. This must be specified if the + * elements contain a spinlock. + * + * On success, *count* elements from the map are updated. + * + * If an error is returned and *errno* is not **EFAULT**, *count* + * is set to the number of successfully processed elements. If + * *errno* is **EFAULT**, up to *count* elements may be been + * deleted. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_LINK_CREATE + * Description + * Attach an eBPF program to a *target_fd* at the specified + * *attach_type* hook and return a file descriptor handle for + * managing the link. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_LINK_UPDATE + * Description + * Update the eBPF program in the specified *link_fd* to + * *new_prog_fd*. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_LINK_GET_FD_BY_ID + * Description + * Open a file descriptor for the eBPF Link corresponding to + * *link_id*. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_LINK_GET_NEXT_ID + * Description + * Fetch the next eBPF link currently loaded into the kernel. + * + * Looks for the eBPF link with an id greater than *start_id* + * and updates *next_id* on success. If no other eBPF links + * remain with ids higher than *start_id*, returns -1 and sets + * *errno* to **ENOENT**. + * + * Return + * Returns zero on success. On error, or when no id remains, -1 + * is returned and *errno* is set appropriately. + * + * BPF_ENABLE_STATS + * Description + * Enable eBPF runtime statistics gathering. + * + * Runtime statistics gathering for the eBPF runtime is disabled + * by default to minimize the corresponding performance overhead. + * This command enables statistics globally. + * + * Multiple programs may independently enable statistics. + * After gathering the desired statistics, eBPF runtime statistics + * may be disabled again by calling **close**\ (2) for the file + * descriptor returned by this function. Statistics will only be + * disabled system-wide when all outstanding file descriptors + * returned by prior calls for this subcommand are closed. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_ITER_CREATE + * Description + * Create an iterator on top of the specified *link_fd* (as + * previously created using **BPF_LINK_CREATE**) and return a + * file descriptor that can be used to trigger the iteration. + * + * If the resulting file descriptor is pinned to the filesystem + * using **BPF_OBJ_PIN**, then subsequent **read**\ (2) syscalls + * for that path will trigger the iterator to read kernel state + * using the eBPF program attached to *link_fd*. + * + * Return + * A new file descriptor (a nonnegative integer), or -1 if an + * error occurred (in which case, *errno* is set appropriately). + * + * BPF_LINK_DETACH + * Description + * Forcefully detach the specified *link_fd* from its + * corresponding attachment point. + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * BPF_PROG_BIND_MAP + * Description + * Bind a map to the lifetime of an eBPF program. + * + * The map identified by *map_fd* is bound to the program + * identified by *prog_fd* and only released when *prog_fd* is + * released. This may be used in cases where metadata should be + * associated with a program which otherwise does not contain any + * references to the map (for example, embedded in the eBPF + * program instructions). + * + * Return + * Returns zero on success. On error, -1 is returned and *errno* + * is set appropriately. + * + * NOTES + * eBPF objects (maps and programs) can be shared between processes. + * + * * After **fork**\ (2), the child inherits file descriptors + * referring to the same eBPF objects. + * * File descriptors referring to eBPF objects can be transferred over + * **unix**\ (7) domain sockets. + * * File descriptors referring to eBPF objects can be duplicated in the + * usual way, using **dup**\ (2) and similar calls. + * * File descriptors referring to eBPF objects can be pinned to the + * filesystem using the **BPF_OBJ_PIN** command of **bpf**\ (2). + * + * An eBPF object is deallocated only after all file descriptors referring + * to the object have been closed and no references remain pinned to the + * filesystem or attached (for example, bound to a program or device). + */ enum bpf_cmd { BPF_MAP_CREATE, BPF_MAP_LOOKUP_ELEM, @@ -247,6 +957,7 @@ enum bpf_attach_type { BPF_XDP_CPUMAP, BPF_SK_LOOKUP, BPF_XDP, + BPF_SK_SKB_VERDICT, __MAX_BPF_ATTACH_TYPE }; @@ -393,11 +1104,24 @@ enum bpf_link_type { * is struct/union. */ #define BPF_PSEUDO_BTF_ID 3 +/* insn[0].src_reg: BPF_PSEUDO_FUNC + * insn[0].imm: insn offset to the func + * insn[1].imm: 0 + * insn[0].off: 0 + * insn[1].off: 0 + * ldimm64 rewrite: address of the function + * verifier type: PTR_TO_FUNC. + */ +#define BPF_PSEUDO_FUNC 4 /* when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative * offset to another bpf function */ #define BPF_PSEUDO_CALL 1 +/* when bpf_call->src_reg == BPF_PSEUDO_KFUNC_CALL, + * bpf_call->imm == btf_id of a BTF_KIND_FUNC in the running kernel + */ +#define BPF_PSEUDO_KFUNC_CALL 2 /* flags for BPF_MAP_UPDATE_ELEM command */ enum { @@ -720,7 +1444,7 @@ union bpf_attr { * parsed and used to produce a manual page. The workflow is the following, * and requires the rst2man utility: * - * $ ./scripts/bpf_helpers_doc.py \ + * $ ./scripts/bpf_doc.py \ * --filename include/uapi/linux/bpf.h > /tmp/bpf-helpers.rst * $ rst2man /tmp/bpf-helpers.rst > /tmp/bpf-helpers.7 * $ man /tmp/bpf-helpers.7 @@ -1765,6 +2489,10 @@ union bpf_attr { * Use with ENCAP_L3/L4 flags to further specify the tunnel * type; *len* is the length of the inner MAC header. * + * * **BPF_F_ADJ_ROOM_ENCAP_L2_ETH**: + * Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the + * L2 type as Ethernet. + * * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be @@ -3915,6 +4643,34 @@ union bpf_attr { * * **BPF_MTU_CHK_RET_FRAG_NEEDED** * * **BPF_MTU_CHK_RET_SEGS_TOOBIG** * + * long bpf_for_each_map_elem(struct bpf_map *map, void *callback_fn, void *callback_ctx, u64 flags) + * Description + * For each element in **map**, call **callback_fn** function with + * **map**, **callback_ctx** and other map-specific parameters. + * The **callback_fn** should be a static function and + * the **callback_ctx** should be a pointer to the stack. + * The **flags** is used to control certain aspects of the helper. + * Currently, the **flags** must be 0. + * + * The following are a list of supported map types and their + * respective expected callback signatures: + * + * BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_PERCPU_HASH, + * BPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH, + * BPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PERCPU_ARRAY + * + * long (\*callback_fn)(struct bpf_map \*map, const void \*key, void \*value, void \*ctx); + * + * For per_cpu maps, the map_value is the value on the cpu where the + * bpf_prog is running. + * + * If **callback_fn** return 0, the helper will continue to the next + * element. If return value is 1, the helper will skip the rest of + * elements and return. Other return values are not used now. + * + * Return + * The number of traversed map elements for success, **-EINVAL** for + * invalid **flags**. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4081,6 +4837,7 @@ union bpf_attr { FN(ima_inode_hash), \ FN(sock_from_file), \ FN(check_mtu), \ + FN(for_each_map_elem), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper @@ -4174,6 +4931,7 @@ enum { BPF_F_ADJ_ROOM_ENCAP_L4_GRE = (1ULL << 3), BPF_F_ADJ_ROOM_ENCAP_L4_UDP = (1ULL << 4), BPF_F_ADJ_ROOM_NO_CSUM_RESET = (1ULL << 5), + BPF_F_ADJ_ROOM_ENCAP_L2_ETH = (1ULL << 6), }; enum { @@ -5211,7 +5969,10 @@ struct bpf_pidns_info { /* User accessible data for SK_LOOKUP programs. Add new fields at the end. */ struct bpf_sk_lookup { - __bpf_md_ptr(struct bpf_sock *, sk); /* Selected socket */ + union { + __bpf_md_ptr(struct bpf_sock *, sk); /* Selected socket */ + __u64 cookie; /* Non-zero if socket was selected in PROG_TEST_RUN */ + }; __u32 family; /* Protocol family (AF_INET, AF_INET6) */ __u32 protocol; /* IP protocol (IPPROTO_TCP, IPPROTO_UDP) */ diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h index 4a42eb48..2c42dcac 100644 --- a/include/uapi/linux/btf.h +++ b/include/uapi/linux/btf.h @@ -52,7 +52,7 @@ struct btf_type { }; }; -#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f) +#define BTF_INFO_KIND(info) (((info) >> 24) & 0x1f) #define BTF_INFO_VLEN(info) ((info) & 0xffff) #define BTF_INFO_KFLAG(info) ((info) >> 31) @@ -72,7 +72,8 @@ struct btf_type { #define BTF_KIND_FUNC_PROTO 13 /* Function Proto */ #define BTF_KIND_VAR 14 /* Variable */ #define BTF_KIND_DATASEC 15 /* Section */ -#define BTF_KIND_MAX BTF_KIND_DATASEC +#define BTF_KIND_FLOAT 16 /* Floating point */ +#define BTF_KIND_MAX BTF_KIND_FLOAT #define NR_BTF_KINDS (BTF_KIND_MAX + 1) /* For some specific BTF_KIND, "struct btf_type" is immediately diff --git a/include/uapi/linux/icmpv6.h b/include/uapi/linux/icmpv6.h index fcea1c50..fa6388c0 100644 --- a/include/uapi/linux/icmpv6.h +++ b/include/uapi/linux/icmpv6.h @@ -140,6 +140,9 @@ struct icmp6hdr { #define ICMPV6_UNK_OPTION 2 #define ICMPV6_HDR_INCOMP 3 +/* Codes for EXT_ECHO (PROBE) */ +#define ICMPV6_EXT_ECHO_REQUEST 160 +#define ICMPV6_EXT_ECHO_REPLY 161 /* * constants for (set|get)sockopt */ diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h index c3e40165..1227b04d 100644 --- a/include/uapi/linux/mptcp.h +++ b/include/uapi/linux/mptcp.h @@ -174,10 +174,21 @@ enum mptcp_event_attr { MPTCP_ATTR_FLAGS, /* u16 */ MPTCP_ATTR_TIMEOUT, /* u32 */ MPTCP_ATTR_IF_IDX, /* s32 */ + MPTCP_ATTR_RESET_REASON,/* u32 */ + MPTCP_ATTR_RESET_FLAGS, /* u32 */ __MPTCP_ATTR_AFTER_LAST }; #define MPTCP_ATTR_MAX (__MPTCP_ATTR_AFTER_LAST - 1) +/* MPTCP Reset reason codes, rfc8684 */ +#define MPTCP_RST_EUNSPEC 0 +#define MPTCP_RST_EMPTCP 1 +#define MPTCP_RST_ERESOURCE 2 +#define MPTCP_RST_EPROHIBIT 3 +#define MPTCP_RST_EWQ2BIG 4 +#define MPTCP_RST_EBADPERF 5 +#define MPTCP_RST_EMIDDLEBOX 6 + #endif /* _MPTCP_H */ diff --git a/include/uapi/linux/nexthop.h b/include/uapi/linux/nexthop.h index b0a56139..37b14b4e 100644 --- a/include/uapi/linux/nexthop.h +++ b/include/uapi/linux/nexthop.h @@ -21,7 +21,10 @@ struct nexthop_grp { }; enum { - NEXTHOP_GRP_TYPE_MPATH, /* default type if not specified */ + NEXTHOP_GRP_TYPE_MPATH, /* hash-threshold nexthop group + * default type if not specified + */ + NEXTHOP_GRP_TYPE_RES, /* resilient nexthop group */ __NEXTHOP_GRP_TYPE_MAX, }; @@ -52,8 +55,50 @@ enum { NHA_FDB, /* flag; nexthop belongs to a bridge fdb */ /* if NHA_FDB is added, OIF, BLACKHOLE, ENCAP cannot be set */ + /* nested; resilient nexthop group attributes */ + NHA_RES_GROUP, + /* nested; nexthop bucket attributes */ + NHA_RES_BUCKET, + __NHA_MAX, }; #define NHA_MAX (__NHA_MAX - 1) + +enum { + NHA_RES_GROUP_UNSPEC, + /* Pad attribute for 64-bit alignment. */ + NHA_RES_GROUP_PAD = NHA_RES_GROUP_UNSPEC, + + /* u16; number of nexthop buckets in a resilient nexthop group */ + NHA_RES_GROUP_BUCKETS, + /* clock_t as u32; nexthop bucket idle timer (per-group) */ + NHA_RES_GROUP_IDLE_TIMER, + /* clock_t as u32; nexthop unbalanced timer */ + NHA_RES_GROUP_UNBALANCED_TIMER, + /* clock_t as u64; nexthop unbalanced time */ + NHA_RES_GROUP_UNBALANCED_TIME, + + __NHA_RES_GROUP_MAX, +}; + +#define NHA_RES_GROUP_MAX (__NHA_RES_GROUP_MAX - 1) + +enum { + NHA_RES_BUCKET_UNSPEC, + /* Pad attribute for 64-bit alignment. */ + NHA_RES_BUCKET_PAD = NHA_RES_BUCKET_UNSPEC, + + /* u16; nexthop bucket index */ + NHA_RES_BUCKET_INDEX, + /* clock_t as u64; nexthop bucket idle time */ + NHA_RES_BUCKET_IDLE_TIME, + /* u32; nexthop id assigned to the nexthop bucket */ + NHA_RES_BUCKET_NH_ID, + + __NHA_RES_BUCKET_MAX, +}; + +#define NHA_RES_BUCKET_MAX (__NHA_RES_BUCKET_MAX - 1) + #endif diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 7ea59cfe..025c40fe 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -190,6 +190,8 @@ enum { TCA_POLICE_PAD, TCA_POLICE_RATE64, TCA_POLICE_PEAKRATE64, + TCA_POLICE_PKTRATE64, + TCA_POLICE_PKTBURST64, __TCA_POLICE_MAX #define TCA_POLICE_RESULT TCA_POLICE_RESULT }; diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index b34b9add..e01efa28 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -178,6 +178,13 @@ enum { RTM_GETVLAN, #define RTM_GETVLAN RTM_GETVLAN + RTM_NEWNEXTHOPBUCKET = 116, +#define RTM_NEWNEXTHOPBUCKET RTM_NEWNEXTHOPBUCKET + RTM_DELNEXTHOPBUCKET, +#define RTM_DELNEXTHOPBUCKET RTM_DELNEXTHOPBUCKET + RTM_GETNEXTHOPBUCKET, +#define RTM_GETNEXTHOPBUCKET RTM_GETNEXTHOPBUCKET + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -283,6 +290,7 @@ enum { #define RTPROT_MROUTED 17 /* Multicast daemon */ #define RTPROT_KEEPALIVED 18 /* Keepalived daemon */ #define RTPROT_BABEL 42 /* Babel daemon */ +#define RTPROT_OPENR 99 /* Open Routing (Open/R) Routes */ #define RTPROT_BGP 186 /* BGP Routes */ #define RTPROT_ISIS 187 /* ISIS Routes */ #define RTPROT_OSPF 188 /* OSPF Routes */ diff --git a/include/utils.h b/include/utils.h index b29c3798..187444d5 100644 --- a/include/utils.h +++ b/include/utils.h @@ -308,6 +308,7 @@ char *find_cgroup2_mount(bool do_mount); __u64 get_cgroup2_id(const char *path); char *get_cgroup2_path(__u64 id, bool full); int get_command_name(const char *pid, char *comm, size_t len); +char *get_task_name(pid_t pid); int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64, struct rtattr *tb[]); diff --git a/ip/ip.c b/ip/ip.c index 4cf09fc3..8e4c6eb5 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -125,7 +125,7 @@ static const struct cmd { { 0 } }; -static int do_cmd(const char *argv0, int argc, char **argv) +static int do_cmd(const char *argv0, int argc, char **argv, bool final) { const struct cmd *c; @@ -134,7 +134,8 @@ static int do_cmd(const char *argv0, int argc, char **argv) return -(c->func(argc-1, argv+1)); } - fprintf(stderr, "Object \"%s\" is unknown, try \"ip help\".\n", argv0); + if (final) + fprintf(stderr, "Object \"%s\" is unknown, try \"ip help\".\n", argv0); return EXIT_FAILURE; } @@ -143,7 +144,7 @@ static int ip_batch_cmd(int argc, char *argv[], void *data) const int *orig_family = data; preferred_family = *orig_family; - return do_cmd(argv[0], argc, argv); + return do_cmd(argv[0], argc, argv, true); } static int batch(const char *name) @@ -313,11 +314,14 @@ int main(int argc, char **argv) rtnl_set_strict_dump(&rth); - if (strlen(basename) > 2) - return do_cmd(basename+2, argc, argv); + if (strlen(basename) > 2) { + int ret = do_cmd(basename+2, argc, argv, false); + if (ret != EXIT_FAILURE) + return ret; + } if (argc > 1) - return do_cmd(argv[1], argc-1, argv+1); + return do_cmd(argv[1], argc-1, argv+1, true); rtnl_close(&rth); usage(); diff --git a/ip/ip_common.h b/ip/ip_common.h index 1fd2ed3a..b5b2b082 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -54,6 +54,7 @@ int print_rule(struct nlmsghdr *n, void *arg); int print_netconf(struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg); int print_nexthop(struct nlmsghdr *n, void *arg); +int print_nexthop_bucket(struct nlmsghdr *n, void *arg); void netns_map_init(void); void netns_nsid_socket_init(void); int print_nsid(struct nlmsghdr *n, void *arg); diff --git a/ip/ipmonitor.c b/ip/ipmonitor.c index 50aa013e..ab1af2eb 100644 --- a/ip/ipmonitor.c +++ b/ip/ipmonitor.c @@ -91,6 +91,12 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl, print_nexthop(n, arg); return 0; + case RTM_NEWNEXTHOPBUCKET: + case RTM_DELNEXTHOPBUCKET: + print_headers(fp, "[NEXTHOPBUCKET]", ctrl); + print_nexthop_bucket(n, arg); + return 0; + case RTM_NEWLINK: case RTM_DELLINK: ll_remember_index(n, NULL); diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c index e1ffafb3..5f490f00 100644 --- a/ip/ipmptcp.c +++ b/ip/ipmptcp.c @@ -17,12 +17,13 @@ static void usage(void) { fprintf(stderr, "Usage: ip mptcp endpoint add ADDRESS [ dev NAME ] [ id ID ]\n" - " [ FLAG-LIST ]\n" + " [ port NR ] [ FLAG-LIST ]\n" " ip mptcp endpoint delete id ID\n" " ip mptcp endpoint show [ id ID ]\n" " ip mptcp endpoint flush\n" " ip mptcp limits set [ subflows NR ] [ add_addr_accepted NR ]\n" " ip mptcp limits show\n" + " ip mptcp monitor\n" "FLAG-LIST := [ FLAG-LIST ] FLAG\n" "FLAG := [ signal | subflow | backup ]\n"); @@ -97,6 +98,7 @@ static int mptcp_parse_opt(int argc, char **argv, struct nlmsghdr *n, bool id_set = false; __u32 index = 0; __u32 flags = 0; + __u16 port = 0; __u8 id = 0; ll_init_map(&rth); @@ -123,6 +125,10 @@ static int mptcp_parse_opt(int argc, char **argv, struct nlmsghdr *n, if (!index) invarg("device does not exist\n", ifname); + } else if (matches(*argv, "port") == 0) { + NEXT_ARG(); + if (get_u16(&port, *argv, 0)) + invarg("expected port", *argv); } else if (get_addr(&address, *argv, AF_UNSPEC) == 0) { addr_set = true; } else { @@ -145,6 +151,8 @@ static int mptcp_parse_opt(int argc, char **argv, struct nlmsghdr *n, addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FLAGS, flags); if (index) addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_IF_IDX, index); + if (port) + addattr16(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_PORT, port); if (addr_set) { int type; @@ -181,8 +189,8 @@ static int print_mptcp_addrinfo(struct rtattr *addrinfo) __u8 family = AF_UNSPEC, addr_attr_type; const char *ifname; unsigned int flags; + __u16 id, port; int index; - __u16 id; parse_rtattr_nested(tb, MPTCP_PM_ADDR_ATTR_MAX, addrinfo); @@ -196,6 +204,11 @@ static int print_mptcp_addrinfo(struct rtattr *addrinfo) print_string(PRINT_ANY, "address", "%s ", format_host_rta(family, tb[addr_attr_type])); } + if (tb[MPTCP_PM_ADDR_ATTR_PORT]) { + port = rta_getattr_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]); + if (port) + print_uint(PRINT_ANY, "port", "port %u ", port); + } if (tb[MPTCP_PM_ADDR_ATTR_ID]) { id = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_ID]); print_uint(PRINT_ANY, "id", "id %u ", id); @@ -385,6 +398,110 @@ static int mptcp_limit_get_set(int argc, char **argv, int cmd) return 0; } +static const char * const event_to_str[] = { + [MPTCP_EVENT_CREATED] = "CREATED", + [MPTCP_EVENT_ESTABLISHED] = "ESTABLISHED", + [MPTCP_EVENT_CLOSED] = "CLOSED", + [MPTCP_EVENT_ANNOUNCED] = "ANNOUNCED", + [MPTCP_EVENT_REMOVED] = "REMOVED", + [MPTCP_EVENT_SUB_ESTABLISHED] = "SF_ESTABLISHED", + [MPTCP_EVENT_SUB_CLOSED] = "SF_CLOSED", + [MPTCP_EVENT_SUB_PRIORITY] = "SF_PRIO", +}; + +static void print_addr(const char *key, int af, struct rtattr *value) +{ + void *data = RTA_DATA(value); + char str[INET6_ADDRSTRLEN]; + + if (inet_ntop(af, data, str, sizeof(str))) + printf(" %s=%s", key, str); +} + +static int mptcp_monitor_msg(struct rtnl_ctrl_data *ctrl, + struct nlmsghdr *n, void *arg) +{ + const struct genlmsghdr *ghdr = NLMSG_DATA(n); + struct rtattr *tb[MPTCP_ATTR_MAX + 1]; + int len = n->nlmsg_len; + + len -= NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) + return -1; + + if (n->nlmsg_type != genl_family) + return 0; + + if (timestamp) + print_timestamp(stdout); + + if (ghdr->cmd >= ARRAY_SIZE(event_to_str)) { + printf("[UNKNOWN %u]\n", ghdr->cmd); + goto out; + } + + if (event_to_str[ghdr->cmd] == NULL) { + printf("[UNKNOWN %u]\n", ghdr->cmd); + goto out; + } + + printf("[%14s]", event_to_str[ghdr->cmd]); + + parse_rtattr(tb, MPTCP_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); + + printf(" token=%08x", rta_getattr_u32(tb[MPTCP_ATTR_TOKEN])); + + if (tb[MPTCP_ATTR_REM_ID]) + printf(" remid=%u", rta_getattr_u8(tb[MPTCP_ATTR_REM_ID])); + if (tb[MPTCP_ATTR_LOC_ID]) + printf(" locid=%u", rta_getattr_u8(tb[MPTCP_ATTR_LOC_ID])); + + if (tb[MPTCP_ATTR_SADDR4]) + print_addr("saddr4", AF_INET, tb[MPTCP_ATTR_SADDR4]); + if (tb[MPTCP_ATTR_DADDR4]) + print_addr("daddr4", AF_INET, tb[MPTCP_ATTR_DADDR4]); + if (tb[MPTCP_ATTR_SADDR6]) + print_addr("saddr6", AF_INET6, tb[MPTCP_ATTR_SADDR6]); + if (tb[MPTCP_ATTR_DADDR6]) + print_addr("daddr6", AF_INET6, tb[MPTCP_ATTR_DADDR6]); + if (tb[MPTCP_ATTR_SPORT]) + printf(" sport=%u", rta_getattr_be16(tb[MPTCP_ATTR_SPORT])); + if (tb[MPTCP_ATTR_DPORT]) + printf(" dport=%u", rta_getattr_be16(tb[MPTCP_ATTR_DPORT])); + if (tb[MPTCP_ATTR_BACKUP]) + printf(" backup=%d", rta_getattr_u8(tb[MPTCP_ATTR_BACKUP])); + if (tb[MPTCP_ATTR_ERROR]) + printf(" error=%d", rta_getattr_u8(tb[MPTCP_ATTR_ERROR])); + if (tb[MPTCP_ATTR_FLAGS]) + printf(" flags=%x", rta_getattr_u16(tb[MPTCP_ATTR_FLAGS])); + if (tb[MPTCP_ATTR_TIMEOUT]) + printf(" timeout=%u", rta_getattr_u32(tb[MPTCP_ATTR_TIMEOUT])); + if (tb[MPTCP_ATTR_IF_IDX]) + printf(" ifindex=%d", rta_getattr_s32(tb[MPTCP_ATTR_IF_IDX])); + if (tb[MPTCP_ATTR_RESET_REASON]) + printf(" reset_reason=%u", rta_getattr_u32(tb[MPTCP_ATTR_RESET_REASON])); + if (tb[MPTCP_ATTR_RESET_FLAGS]) + printf(" reset_flags=0x%x", rta_getattr_u32(tb[MPTCP_ATTR_RESET_FLAGS])); + + puts(""); +out: + fflush(stdout); + return 0; +} + +static int mptcp_monitor(void) +{ + if (genl_add_mcast_grp(&genl_rth, genl_family, MPTCP_PM_EV_GRP_NAME) < 0) { + perror("can't subscribe to mptcp events"); + return 1; + } + + if (rtnl_listen(&genl_rth, mptcp_monitor_msg, stdout) < 0) + return 2; + + return 0; +} + int do_mptcp(int argc, char **argv) { if (argc == 0) @@ -429,6 +546,14 @@ int do_mptcp(int argc, char **argv) MPTCP_PM_CMD_GET_LIMITS); } + if (matches(*argv, "monitor") == 0) { + NEXT_ARG_FWD(); + if (argc == 0) + return mptcp_monitor(); + + goto unknown; + } + unknown: fprintf(stderr, "Command \"%s\" is unknown, try \"ip mptcp help\".\n", *argv); diff --git a/ip/ipnexthop.c b/ip/ipnexthop.c index f0658a9c..9478aa52 100644 --- a/ip/ipnexthop.c +++ b/ip/ipnexthop.c @@ -21,6 +21,8 @@ static struct { unsigned int master; unsigned int proto; unsigned int fdb; + unsigned int id; + unsigned int nhid; } filter; enum { @@ -39,11 +41,19 @@ static void usage(void) "Usage: ip nexthop { list | flush } [ protocol ID ] SELECTOR\n" " ip nexthop { add | replace } id ID NH [ protocol ID ]\n" " ip nexthop { get | del } id ID\n" + " ip nexthop bucket list BUCKET_SELECTOR\n" + " ip nexthop bucket get id ID index INDEX\n" "SELECTOR := [ id ID ] [ dev DEV ] [ vrf NAME ] [ master DEV ]\n" " [ groups ] [ fdb ]\n" + "BUCKET_SELECTOR := SELECTOR | [ nhid ID ]\n" "NH := { blackhole | [ via ADDRESS ] [ dev DEV ] [ onlink ]\n" - " [ encap ENCAPTYPE ENCAPHDR ] | group GROUP [ fdb ] }\n" + " [ encap ENCAPTYPE ENCAPHDR ] |\n" + " group GROUP [ fdb ] [ type TYPE [ TYPE_ARGS ] ] }\n" "GROUP := [ //... ]\n" + "TYPE := { mpath | resilient }\n" + "TYPE_ARGS := [ RESILIENT_ARGS ]\n" + "RESILIENT_ARGS := [ buckets BUCKETS ] [ idle_timer IDLE ]\n" + " [ unbalanced_timer UNBALANCED ]\n" "ENCAPTYPE := [ mpls ]\n" "ENCAPHDR := [ MPLSLABEL ]\n"); exit(-1); @@ -80,6 +90,36 @@ static int nh_dump_filter(struct nlmsghdr *nlh, int reqlen) return 0; } +static int nh_dump_bucket_filter(struct nlmsghdr *nlh, int reqlen) +{ + struct rtattr *nest; + int err = 0; + + err = nh_dump_filter(nlh, reqlen); + if (err) + return err; + + if (filter.id) { + err = addattr32(nlh, reqlen, NHA_ID, filter.id); + if (err) + return err; + } + + if (filter.nhid) { + nest = addattr_nest(nlh, reqlen, NHA_RES_BUCKET); + nest->rta_type |= NLA_F_NESTED; + + err = addattr32(nlh, reqlen, NHA_RES_BUCKET_NH_ID, + filter.nhid); + if (err) + return err; + + addattr_nest_end(nlh, nest); + } + + return err; +} + static struct rtnl_handle rth_del = { .fd = -1 }; static int delete_nexthop(__u32 id) @@ -201,6 +241,93 @@ static void print_nh_group(FILE *fp, const struct rtattr *grps_attr) close_json_array(PRINT_JSON, NULL); } +static const char *nh_group_type_name(__u16 type) +{ + switch (type) { + case NEXTHOP_GRP_TYPE_MPATH: + return "mpath"; + case NEXTHOP_GRP_TYPE_RES: + return "resilient"; + default: + return ""; + } +} + +static void print_nh_group_type(FILE *fp, const struct rtattr *grp_type_attr) +{ + __u16 type = rta_getattr_u16(grp_type_attr); + + if (type == NEXTHOP_GRP_TYPE_MPATH) + /* Do not print type in order not to break existing output. */ + return; + + print_string(PRINT_ANY, "type", "type %s ", nh_group_type_name(type)); +} + +static void print_nh_res_group(FILE *fp, const struct rtattr *res_grp_attr) +{ + struct rtattr *tb[NHA_RES_GROUP_MAX + 1]; + struct rtattr *rta; + struct timeval tv; + + parse_rtattr_nested(tb, NHA_RES_GROUP_MAX, res_grp_attr); + + open_json_object("resilient_args"); + + if (tb[NHA_RES_GROUP_BUCKETS]) + print_uint(PRINT_ANY, "buckets", "buckets %u ", + rta_getattr_u16(tb[NHA_RES_GROUP_BUCKETS])); + + if (tb[NHA_RES_GROUP_IDLE_TIMER]) { + rta = tb[NHA_RES_GROUP_IDLE_TIMER]; + __jiffies_to_tv(&tv, rta_getattr_u32(rta)); + print_tv(PRINT_ANY, "idle_timer", "idle_timer %g ", &tv); + } + + if (tb[NHA_RES_GROUP_UNBALANCED_TIMER]) { + rta = tb[NHA_RES_GROUP_UNBALANCED_TIMER]; + __jiffies_to_tv(&tv, rta_getattr_u32(rta)); + print_tv(PRINT_ANY, "unbalanced_timer", "unbalanced_timer %g ", + &tv); + } + + if (tb[NHA_RES_GROUP_UNBALANCED_TIME]) { + rta = tb[NHA_RES_GROUP_UNBALANCED_TIME]; + __jiffies_to_tv(&tv, rta_getattr_u32(rta)); + print_tv(PRINT_ANY, "unbalanced_time", "unbalanced_time %g ", + &tv); + } + + close_json_object(); +} + +static void print_nh_res_bucket(FILE *fp, const struct rtattr *res_bucket_attr) +{ + struct rtattr *tb[NHA_RES_BUCKET_MAX + 1]; + + parse_rtattr_nested(tb, NHA_RES_BUCKET_MAX, res_bucket_attr); + + open_json_object("bucket"); + + if (tb[NHA_RES_BUCKET_INDEX]) + print_uint(PRINT_ANY, "index", "index %u ", + rta_getattr_u16(tb[NHA_RES_BUCKET_INDEX])); + + if (tb[NHA_RES_BUCKET_IDLE_TIME]) { + struct rtattr *rta = tb[NHA_RES_BUCKET_IDLE_TIME]; + struct timeval tv; + + __jiffies_to_tv(&tv, rta_getattr_u64(rta)); + print_tv(PRINT_ANY, "idle_time", "idle_time %g ", &tv); + } + + if (tb[NHA_RES_BUCKET_NH_ID]) + print_uint(PRINT_ANY, "nhid", "nhid %u ", + rta_getattr_u32(tb[NHA_RES_BUCKET_NH_ID])); + + close_json_object(); +} + int print_nexthop(struct nlmsghdr *n, void *arg) { struct nhmsg *nhm = NLMSG_DATA(n); @@ -227,7 +354,7 @@ int print_nexthop(struct nlmsghdr *n, void *arg) if (filter.proto && filter.proto != nhm->nh_protocol) return 0; - parse_rtattr(tb, NHA_MAX, RTM_NHA(nhm), len); + parse_rtattr_flags(tb, NHA_MAX, RTM_NHA(nhm), len, NLA_F_NESTED); open_json_object(NULL); @@ -241,6 +368,12 @@ int print_nexthop(struct nlmsghdr *n, void *arg) if (tb[NHA_GROUP]) print_nh_group(fp, tb[NHA_GROUP]); + if (tb[NHA_GROUP_TYPE]) + print_nh_group_type(fp, tb[NHA_GROUP_TYPE]); + + if (tb[NHA_RES_GROUP]) + print_nh_res_group(fp, tb[NHA_RES_GROUP]); + if (tb[NHA_ENCAP]) lwt_print_encap(fp, tb[NHA_ENCAP_TYPE], tb[NHA_ENCAP]); @@ -275,6 +408,50 @@ int print_nexthop(struct nlmsghdr *n, void *arg) return 0; } +int print_nexthop_bucket(struct nlmsghdr *n, void *arg) +{ + struct nhmsg *nhm = NLMSG_DATA(n); + struct rtattr *tb[NHA_MAX+1]; + FILE *fp = (FILE *)arg; + int len; + + if (n->nlmsg_type != RTM_DELNEXTHOPBUCKET && + n->nlmsg_type != RTM_NEWNEXTHOPBUCKET) { + fprintf(stderr, "Not a nexthop bucket: %08x %08x %08x\n", + n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); + return -1; + } + + len = n->nlmsg_len - NLMSG_SPACE(sizeof(*nhm)); + if (len < 0) { + close_json_object(); + fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); + return -1; + } + + parse_rtattr_flags(tb, NHA_MAX, RTM_NHA(nhm), len, NLA_F_NESTED); + + open_json_object(NULL); + + if (n->nlmsg_type == RTM_DELNEXTHOP) + print_bool(PRINT_ANY, "deleted", "Deleted ", true); + + if (tb[NHA_ID]) + print_uint(PRINT_ANY, "id", "id %u ", + rta_getattr_u32(tb[NHA_ID])); + + if (tb[NHA_RES_BUCKET]) + print_nh_res_bucket(fp, tb[NHA_RES_BUCKET]); + + print_rt_flags(fp, nhm->nh_flags); + + print_string(PRINT_FP, NULL, "%s", "\n"); + close_json_object(); + fflush(fp); + + return 0; +} + static int add_nh_group_attr(struct nlmsghdr *n, int maxlen, char *argv) { struct nexthop_grp *grps = NULL; @@ -331,6 +508,110 @@ out: return err; } +static int read_nh_group_type(const char *name) +{ + if (strcmp(name, "mpath") == 0) + return NEXTHOP_GRP_TYPE_MPATH; + else if (strcmp(name, "resilient") == 0) + return NEXTHOP_GRP_TYPE_RES; + + return __NEXTHOP_GRP_TYPE_MAX; +} + +static void parse_nh_group_type_res(struct nlmsghdr *n, int maxlen, int *argcp, + char ***argvp) +{ + char **argv = *argvp; + struct rtattr *nest; + int argc = *argcp; + + if (!NEXT_ARG_OK()) + return; + + nest = addattr_nest(n, maxlen, NHA_RES_GROUP); + nest->rta_type |= NLA_F_NESTED; + + NEXT_ARG_FWD(); + while (argc > 0) { + if (strcmp(*argv, "buckets") == 0) { + __u16 buckets; + + NEXT_ARG(); + if (get_u16(&buckets, *argv, 0)) + invarg("invalid buckets value", *argv); + + addattr16(n, maxlen, NHA_RES_GROUP_BUCKETS, buckets); + } else if (strcmp(*argv, "idle_timer") == 0) { + __u32 idle_timer; + + NEXT_ARG(); + if (get_unsigned(&idle_timer, *argv, 0) || + idle_timer >= ~0UL / 100) + invarg("invalid idle timer value", *argv); + + addattr32(n, maxlen, NHA_RES_GROUP_IDLE_TIMER, + idle_timer * 100); + } else if (strcmp(*argv, "unbalanced_timer") == 0) { + __u32 unbalanced_timer; + + NEXT_ARG(); + if (get_unsigned(&unbalanced_timer, *argv, 0) || + unbalanced_timer >= ~0UL / 100) + invarg("invalid unbalanced timer value", *argv); + + addattr32(n, maxlen, NHA_RES_GROUP_UNBALANCED_TIMER, + unbalanced_timer * 100); + } else { + break; + } + argc--; argv++; + } + + /* argv is currently the first unparsed argument, but ipnh_modify() + * will move to the next, so step back. + */ + *argcp = argc + 1; + *argvp = argv - 1; + + addattr_nest_end(n, nest); +} + +static void parse_nh_group_type(struct nlmsghdr *n, int maxlen, int *argcp, + char ***argvp) +{ + char **argv = *argvp; + int argc = *argcp; + __u16 type; + + NEXT_ARG(); + type = read_nh_group_type(*argv); + if (type > NEXTHOP_GRP_TYPE_MAX) + invarg("\"type\" value is invalid\n", *argv); + + switch (type) { + case NEXTHOP_GRP_TYPE_MPATH: + /* No additional arguments */ + break; + case NEXTHOP_GRP_TYPE_RES: + parse_nh_group_type_res(n, maxlen, &argc, &argv); + break; + } + + *argcp = argc; + *argvp = argv; + + addattr16(n, maxlen, NHA_GROUP_TYPE, type); +} + +static int ipnh_parse_id(const char *argv) +{ + __u32 id; + + if (get_unsigned(&id, argv, 0)) + invarg("invalid id value", argv); + return id; +} + static int ipnh_modify(int cmd, unsigned int flags, int argc, char **argv) { struct { @@ -347,12 +628,9 @@ static int ipnh_modify(int cmd, unsigned int flags, int argc, char **argv) while (argc > 0) { if (!strcmp(*argv, "id")) { - __u32 id; - NEXT_ARG(); - if (get_unsigned(&id, *argv, 0)) - invarg("invalid id value", *argv); - addattr32(&req.n, sizeof(req), NHA_ID, id); + addattr32(&req.n, sizeof(req), NHA_ID, + ipnh_parse_id(*argv)); } else if (!strcmp(*argv, "dev")) { int ifindex; @@ -407,6 +685,8 @@ static int ipnh_modify(int cmd, unsigned int flags, int argc, char **argv) if (add_nh_group_attr(&req.n, sizeof(req), *argv)) invarg("\"group\" value is invalid\n", *argv); + } else if (!strcmp(*argv, "type")) { + parse_nh_group_type(&req.n, sizeof(req), &argc, &argv); } else if (matches(*argv, "protocol") == 0) { __u32 prot; @@ -464,6 +744,24 @@ static int ipnh_get_id(__u32 id) return 0; } +static int ipnh_list_flush_id(__u32 id, int action) +{ + int err; + + if (action == IPNH_LIST) + return ipnh_get_id(id); + + if (rtnl_open(&rth_del, 0) < 0) { + fprintf(stderr, "Cannot open rtnetlink\n"); + return EXIT_FAILURE; + } + + err = delete_nexthop(id); + rtnl_close(&rth_del); + + return err; +} + static int ipnh_list_flush(int argc, char **argv, int action) { unsigned int all = (argc == 0); @@ -489,12 +787,8 @@ static int ipnh_list_flush(int argc, char **argv, int action) if (!filter.master) invarg("VRF does not exist\n", *argv); } else if (!strcmp(*argv, "id")) { - __u32 id; - NEXT_ARG(); - if (get_unsigned(&id, *argv, 0)) - invarg("invalid id value", *argv); - return ipnh_get_id(id); + return ipnh_list_flush_id(ipnh_parse_id(*argv), action); } else if (!matches(*argv, "protocol")) { __u32 proto; @@ -540,8 +834,7 @@ static int ipnh_get(int argc, char **argv) while (argc > 0) { if (!strcmp(*argv, "id")) { NEXT_ARG(); - if (get_unsigned(&id, *argv, 0)) - invarg("invalid id value", *argv); + id = ipnh_parse_id(*argv); } else { usage(); } @@ -556,6 +849,151 @@ static int ipnh_get(int argc, char **argv) return ipnh_get_id(id); } +static int ipnh_bucket_list(int argc, char **argv) +{ + while (argc > 0) { + if (!matches(*argv, "dev")) { + NEXT_ARG(); + filter.ifindex = ll_name_to_index(*argv); + if (!filter.ifindex) + invarg("Device does not exist\n", *argv); + } else if (!matches(*argv, "master")) { + NEXT_ARG(); + filter.master = ll_name_to_index(*argv); + if (!filter.master) + invarg("Device does not exist\n", *argv); + } else if (matches(*argv, "vrf") == 0) { + NEXT_ARG(); + if (!name_is_vrf(*argv)) + invarg("Invalid VRF\n", *argv); + filter.master = ll_name_to_index(*argv); + if (!filter.master) + invarg("VRF does not exist\n", *argv); + } else if (!strcmp(*argv, "id")) { + NEXT_ARG(); + filter.id = ipnh_parse_id(*argv); + } else if (!strcmp(*argv, "nhid")) { + NEXT_ARG(); + filter.nhid = ipnh_parse_id(*argv); + } else if (matches(*argv, "help") == 0) { + usage(); + } else { + invarg("", *argv); + } + argc--; argv++; + } + + if (rtnl_nexthop_bucket_dump_req(&rth, preferred_family, + nh_dump_bucket_filter) < 0) { + perror("Cannot send dump request"); + return -2; + } + + new_json_obj(json); + + if (rtnl_dump_filter(&rth, print_nexthop_bucket, stdout) < 0) { + fprintf(stderr, "Dump terminated\n"); + return -2; + } + + delete_json_obj(); + fflush(stdout); + + return 0; +} + +static int ipnh_bucket_get_id(__u32 id, __u16 bucket_index) +{ + struct { + struct nlmsghdr n; + struct nhmsg nhm; + char buf[1024]; + } req = { + .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)), + .n.nlmsg_flags = NLM_F_REQUEST, + .n.nlmsg_type = RTM_GETNEXTHOPBUCKET, + .nhm.nh_family = preferred_family, + }; + struct nlmsghdr *answer; + struct rtattr *nest; + + addattr32(&req.n, sizeof(req), NHA_ID, id); + + nest = addattr_nest(&req.n, sizeof(req), NHA_RES_BUCKET); + nest->rta_type |= NLA_F_NESTED; + + addattr16(&req.n, sizeof(req), NHA_RES_BUCKET_INDEX, bucket_index); + + addattr_nest_end(&req.n, nest); + + if (rtnl_talk(&rth, &req.n, &answer) < 0) + return -2; + + new_json_obj(json); + + if (print_nexthop_bucket(answer, (void *)stdout) < 0) { + free(answer); + return -1; + } + + delete_json_obj(); + fflush(stdout); + + free(answer); + + return 0; +} + +static int ipnh_bucket_get(int argc, char **argv) +{ + bool bucket_valid = false; + __u16 bucket_index; + __u32 id = 0; + + while (argc > 0) { + if (!strcmp(*argv, "id")) { + NEXT_ARG(); + id = ipnh_parse_id(*argv); + } else if (!strcmp(*argv, "index")) { + NEXT_ARG(); + if (get_u16(&bucket_index, *argv, 0)) + invarg("invalid bucket index value", *argv); + bucket_valid = true; + } else { + usage(); + } + argc--; argv++; + } + + if (!id || !bucket_valid) { + usage(); + return -1; + } + + return ipnh_bucket_get_id(id, bucket_index); +} + +static int do_ipnh_bucket(int argc, char **argv) +{ + if (argc < 1) + return ipnh_bucket_list(0, NULL); + + if (!matches(*argv, "list") || + !matches(*argv, "show") || + !matches(*argv, "lst")) + return ipnh_bucket_list(argc-1, argv+1); + + if (!matches(*argv, "get")) + return ipnh_bucket_get(argc-1, argv+1); + + if (!matches(*argv, "help")) + usage(); + + fprintf(stderr, + "Command \"%s\" is unknown, try \"ip nexthop help\".\n", *argv); + exit(-1); +} + int do_ipnh(int argc, char **argv) { if (argc < 1) @@ -581,6 +1019,9 @@ int do_ipnh(int argc, char **argv) if (!matches(*argv, "flush")) return ipnh_list_flush(argc-1, argv+1, IPNH_FLUSH); + if (!matches(*argv, "bucket")) + return do_ipnh_bucket(argc-1, argv+1); + if (!matches(*argv, "help")) usage(); diff --git a/ip/iptuntap.c b/ip/iptuntap.c index e9cc7c0f..9cdb4a80 100644 --- a/ip/iptuntap.c +++ b/ip/iptuntap.c @@ -260,35 +260,6 @@ static void print_flags(long flags) close_json_array(PRINT_JSON, NULL); } -static char *pid_name(pid_t pid) -{ - char *comm; - FILE *f; - int err; - - err = asprintf(&comm, "/proc/%d/comm", pid); - if (err < 0) - return NULL; - - f = fopen(comm, "r"); - free(comm); - if (!f) { - perror("fopen"); - return NULL; - } - - if (fscanf(f, "%ms\n", &comm) != 1) { - perror("fscanf"); - comm = NULL; - } - - - if (fclose(f)) - perror("fclose"); - - return comm; -} - static void show_processes(const char *name) { glob_t globbuf = { }; @@ -346,7 +317,7 @@ static void show_processes(const char *name) } else if (err == 2 && !strcmp("iff", key) && !strcmp(name, value)) { - char *pname = pid_name(pid); + char *pname = get_task_name(pid); print_string(PRINT_ANY, "name", "%s", pname ? : ""); diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c index 8a794032..1c59596a 100644 --- a/ip/ipxfrm.c +++ b/ip/ipxfrm.c @@ -907,6 +907,14 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, fprintf(fp, "if_id %#x", if_id); fprintf(fp, "%s", _SL_); } + if (tb[XFRMA_TFCPAD]) { + __u32 tfcpad = rta_getattr_u32(tb[XFRMA_TFCPAD]); + + if (prefix) + fputs(prefix, fp); + fprintf(fp, "tfcpad %u", tfcpad); + fprintf(fp, "%s", _SL_); + } } static int xfrm_selector_iszero(struct xfrm_selector *s) diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c index a4f452fa..6fee7efd 100644 --- a/ip/xfrm_state.c +++ b/ip/xfrm_state.c @@ -63,7 +63,7 @@ static void usage(void) " [ coa ADDR[/PLEN] ] [ ctx CTX ] [ extra-flag EXTRA-FLAG-LIST ]\n" " [ offload [dev DEV] dir DIR ]\n" " [ output-mark OUTPUT-MARK [ mask MASK ] ]\n" - " [ if_id IF_ID ]\n" + " [ if_id IF_ID ] [ tfcpad LENGTH ]\n" "Usage: ip xfrm state allocspi ID [ mode MODE ] [ mark MARK [ mask MASK ] ]\n" " [ reqid REQID ] [ seq SEQ ] [ min SPI max SPI ]\n" "Usage: ip xfrm state { delete | get } ID [ mark MARK [ mask MASK ] ]\n" @@ -331,6 +331,7 @@ static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) struct xfrm_mark output_mark = {0, 0}; bool is_if_id_set = false; __u32 if_id = 0; + __u32 tfcpad = 0; while (argc > 0) { if (strcmp(*argv, "mode") == 0) { @@ -465,6 +466,10 @@ static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) if (get_u32(&if_id, *argv, 0)) invarg("value after \"if_id\" is invalid", *argv); is_if_id_set = true; + } else if (strcmp(*argv, "tfcpad") == 0) { + NEXT_ARG(); + if (get_u32(&tfcpad, *argv, 0)) + invarg("value after \"tfcpad\" is invalid", *argv); } else { /* try to assume ALGO */ int type = xfrm_algotype_getbyname(*argv); @@ -650,6 +655,9 @@ static int xfrm_state_modify(int cmd, unsigned int flags, int argc, char **argv) if (is_if_id_set) addattr32(&req.n, sizeof(req.buf), XFRMA_IF_ID, if_id); + if (tfcpad) + addattr32(&req.n, sizeof(req.buf), XFRMA_TFCPAD, tfcpad); + if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { switch (req.xsinfo.mode) { case XFRM_MODE_TRANSPORT: diff --git a/lib/fs.c b/lib/fs.c index ee0b130b..f161d888 100644 --- a/lib/fs.c +++ b/lib/fs.c @@ -316,3 +316,27 @@ int get_command_name(const char *pid, char *comm, size_t len) return 0; } + +char *get_task_name(pid_t pid) +{ + char *comm; + FILE *f; + + if (!pid) + return NULL; + + if (asprintf(&comm, "/proc/%d/comm", pid) < 0) + return NULL; + + f = fopen(comm, "r"); + if (!f) + return NULL; + + if (fscanf(f, "%ms\n", &comm) != 1) + comm = NULL; + + fclose(f); + + return comm; +} + diff --git a/lib/json_print.c b/lib/json_print.c index 994a2f8d..e3a88375 100644 --- a/lib/json_print.c +++ b/lib/json_print.c @@ -299,6 +299,19 @@ int print_color_null(enum output_type type, return ret; } +int print_color_tv(enum output_type type, + enum color_attr color, + const char *key, + const char *fmt, + const struct timeval *tv) +{ + double usecs = tv->tv_usec; + double secs = tv->tv_sec; + double time = secs + usecs / 1000000; + + return print_color_float(type, color, key, fmt, time); +} + /* Print line separator (if not in JSON mode) */ void print_nl(void) { diff --git a/lib/libgenl.c b/lib/libgenl.c index f2ce698f..4c51d47a 100644 --- a/lib/libgenl.c +++ b/lib/libgenl.c @@ -67,6 +67,72 @@ int genl_resolve_family(struct rtnl_handle *grth, const char *family) return fnum; } +static int genl_parse_grps(struct rtattr *attr, const char *name, unsigned int *id) +{ + const struct rtattr *pos; + + rtattr_for_each_nested(pos, attr) { + struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1]; + + parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, pos); + + if (tb[CTRL_ATTR_MCAST_GRP_NAME] && tb[CTRL_ATTR_MCAST_GRP_ID]) { + if (strcmp(name, rta_getattr_str(tb[CTRL_ATTR_MCAST_GRP_NAME])) == 0) { + *id = rta_getattr_u32(tb[CTRL_ATTR_MCAST_GRP_ID]); + return 0; + } + } + } + + return -1; +} + +int genl_add_mcast_grp(struct rtnl_handle *grth, __u16 fnum, const char *group) +{ + GENL_REQUEST(req, 1024, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY, + NLM_F_REQUEST); + struct rtattr *tb[CTRL_ATTR_MAX + 1]; + struct nlmsghdr *answer = NULL; + struct genlmsghdr *ghdr; + struct rtattr *attrs; + int len, ret = -1; + unsigned int id; + + addattr16(&req.n, sizeof(req), CTRL_ATTR_FAMILY_ID, fnum); + + if (rtnl_talk(grth, &req.n, &answer) < 0) { + fprintf(stderr, "Error talking to the kernel\n"); + return -2; + } + + ghdr = NLMSG_DATA(answer); + len = answer->nlmsg_len; + + if (answer->nlmsg_type != GENL_ID_CTRL) + goto err_free; + + len -= NLMSG_LENGTH(GENL_HDRLEN); + if (len < 0) + goto err_free; + + attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN); + parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len); + + if (tb[CTRL_ATTR_MCAST_GROUPS] == NULL) { + fprintf(stderr, "Missing mcast groups TLV\n"); + goto err_free; + } + + if (genl_parse_grps(tb[CTRL_ATTR_MCAST_GROUPS], group, &id) < 0) + goto err_free; + + ret = rtnl_add_nl_group(grth, id); + +err_free: + free(answer); + return ret; +} + int genl_init_handle(struct rtnl_handle *grth, const char *family, int *genl_family) { diff --git a/lib/libnetlink.c b/lib/libnetlink.c index c958aa57..2f2cc1fe 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -282,6 +282,32 @@ int rtnl_nexthopdump_req(struct rtnl_handle *rth, int family, return send(rth->fd, &req, sizeof(req), 0); } +int rtnl_nexthop_bucket_dump_req(struct rtnl_handle *rth, int family, + req_filter_fn_t filter_fn) +{ + struct { + struct nlmsghdr nlh; + struct nhmsg nhm; + char buf[128]; + } req = { + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)), + .nlh.nlmsg_type = RTM_GETNEXTHOPBUCKET, + .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .nlh.nlmsg_seq = rth->dump = ++rth->seq, + .nhm.nh_family = family, + }; + + if (filter_fn) { + int err; + + err = filter_fn(&req.nlh, sizeof(req)); + if (err) + return err; + } + + return send(rth->fd, &req, sizeof(req), 0); +} + int rtnl_addrdump_req(struct rtnl_handle *rth, int family, req_filter_fn_t filter_fn) { @@ -424,6 +450,25 @@ int rtnl_mdbdump_req(struct rtnl_handle *rth, int family) return send(rth->fd, &req, sizeof(req), 0); } +int rtnl_brvlandump_req(struct rtnl_handle *rth, int family, __u32 dump_flags) +{ + struct { + struct nlmsghdr nlh; + struct br_vlan_msg bvm; + char buf[256]; + } req = { + .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)), + .nlh.nlmsg_type = RTM_GETVLAN, + .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .nlh.nlmsg_seq = rth->dump = ++rth->seq, + .bvm.family = family, + }; + + addattr32(&req.nlh, sizeof(req), BRIDGE_VLANDB_DUMP_FLAGS, dump_flags); + + return send(rth->fd, &req, sizeof(req), 0); +} + int rtnl_netconfdump_req(struct rtnl_handle *rth, int family) { struct { diff --git a/lib/mnl_utils.c b/lib/mnl_utils.c index 4f699455..d5abff58 100644 --- a/lib/mnl_utils.c +++ b/lib/mnl_utils.c @@ -196,19 +196,28 @@ void mnlu_gen_socket_close(struct mnlu_gen_socket *nlg) free(nlg->buf); } -struct nlmsghdr *mnlu_gen_socket_cmd_prepare(struct mnlu_gen_socket *nlg, - uint8_t cmd, uint16_t flags) +struct nlmsghdr * +_mnlu_gen_socket_cmd_prepare(struct mnlu_gen_socket *nlg, + uint8_t cmd, uint16_t flags, + uint32_t id, uint8_t version) { struct genlmsghdr hdr = {}; struct nlmsghdr *nlh; hdr.cmd = cmd; - hdr.version = nlg->version; - nlh = mnlu_msg_prepare(nlg->buf, nlg->family, flags, &hdr, sizeof(hdr)); + hdr.version = version; + nlh = mnlu_msg_prepare(nlg->buf, id, flags, &hdr, sizeof(hdr)); nlg->seq = nlh->nlmsg_seq; return nlh; } +struct nlmsghdr *mnlu_gen_socket_cmd_prepare(struct mnlu_gen_socket *nlg, + uint8_t cmd, uint16_t flags) +{ + return _mnlu_gen_socket_cmd_prepare(nlg, cmd, flags, nlg->family, + nlg->version); +} + int mnlu_gen_socket_sndrcv(struct mnlu_gen_socket *nlg, const struct nlmsghdr *nlh, mnl_cb_t data_cb, void *data) { @@ -229,3 +238,11 @@ int mnlu_gen_socket_sndrcv(struct mnlu_gen_socket *nlg, const struct nlmsghdr *n } return 0; } + +int mnlu_gen_socket_recv_run(struct mnlu_gen_socket *nlg, mnl_cb_t cb, + void *data) +{ + return mnlu_socket_recv_run(nlg->nl, nlg->seq, nlg->buf, + MNL_SOCKET_BUFFER_SIZE, + cb, data); +} diff --git a/man/man8/bridge.8 b/man/man8/bridge.8 index 9d8663bd..eec7df43 100644 --- a/man/man8/bridge.8 +++ b/man/man8/bridge.8 @@ -138,13 +138,22 @@ bridge \- show / manipulate bridge addresses and devices .BR pvid " ] [ " untagged " ] [ " .BR self " ] [ " master " ] " +.ti -8 +.BR "bridge vlan set" +.B dev +.I DEV +.B vid +.IR VID " [ " +.B state +.IR STP_STATE " ] " + .ti -8 .BR "bridge vlan" " [ " show " | " tunnelshow " ] [ " .B dev .IR DEV " ]" .ti -8 -.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " ]" +.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " | " vlan " ]" .SH OPTIONS @@ -162,7 +171,7 @@ As a rule, the information is statistics or some time values. .TP .BR "\-d" , " \-details" -print detailed information about MDB router ports. +print detailed information about bridge vlan filter entries or MDB router ports. .TP .BR "\-n" , " \-net" , " \-netns " @@ -813,10 +822,70 @@ The .BR "pvid " and " untagged" flags are ignored. +.SS bridge vlan set - change vlan filter entry's options + +This command changes vlan filter entry's options. + +.TP +.BI dev " NAME" +the interface with which this vlan is associated. + +.TP +.BI vid " VID" +the VLAN ID that identifies the vlan. + +.TP +.BI state " STP_STATE " +the operation state of the vlan. One may enter STP state name (case insensitive), or one of the +numbers below. Negative inputs are ignored, and unrecognized names return an +error. Note that the state is set only for the vlan of the specified device, e.g. if it is +a bridge port then the state will be set only for the vlan of the port. + +.B 0 +- vlan is in STP +.B DISABLED +state. Make this vlan completely inactive for STP. This is also called +BPDU filter and could be used to disable STP on an untrusted vlan. +.sp + +.B 1 +- vlan is in STP +.B LISTENING +state. Only valid if STP is enabled on the bridge. In this +state the vlan listens for STP BPDUs and drops all other traffic frames. +.sp + +.B 2 +- vlan is in STP +.B LEARNING +state. Only valid if STP is enabled on the bridge. In this +state the vlan will accept traffic only for the purpose of updating MAC +address tables. +.sp + +.B 3 +- vlan is in STP +.B FORWARDING +state. This is the default vlan state. +.sp + +.B 4 +- vlan is in STP +.B BLOCKING +state. Only valid if STP is enabled on the bridge. This state +is used during the STP election process. In this state, the vlan will only process +STP BPDUs. +.sp + .SS bridge vlan show - list vlan configuration. This command displays the current VLAN filter table. +.PP +With the +.B -details +option, the command becomes verbose. It displays the per-vlan options. + .PP With the .B -statistics @@ -842,7 +911,7 @@ command is the first in the command line and then the object list follows: .I OBJECT-LIST is the list of object types that we want to monitor. It may contain -.BR link ", " fdb ", and " mdb "." +.BR link ", " fdb ", " vlan " and " mdb "." If no .B file argument is given, diff --git a/man/man8/ip-mptcp.8 b/man/man8/ip-mptcp.8 index ef8409ea..22335b61 100644 --- a/man/man8/ip-mptcp.8 +++ b/man/man8/ip-mptcp.8 @@ -20,6 +20,8 @@ ip-mptcp \- MPTCP path manager configuration .ti -8 .BR "ip mptcp endpoint add " .IR IFADDR +.RB "[ " port +.IR PORT " ]" .RB "[ " dev .IR IFNAME " ]" .RB "[ " id @@ -65,6 +67,9 @@ ip-mptcp \- MPTCP path manager configuration .ti -8 .BR "ip mptcp limits show" +.ti -8 +.BR "ip mptcp monitor" + .SH DESCRIPTION MPTCP is a transport protocol built on top of TCP that allows TCP @@ -87,6 +92,12 @@ ip mptcp endpoint flush flush all existing MPTCP endpoints .TE .TP +.IR PORT +When a port number is specified, incoming MPTCP subflows for already +established MPTCP sockets will be accepted on the specified port, regardless +the original listener port accepting the first MPTCP subflow and/or +this peer being actually on the client side. + .IR ID is a unique numeric identifier for the given endpoint @@ -137,5 +148,10 @@ each accepted ADD_ADDR option, respecting the .IR SUBFLOW_NR limit. +.sp +.PP +.B monitor +displays creation and deletion of MPTCP connections as well as addition or removal of remote addresses and subflows. + .SH AUTHOR Original Manpage by Paolo Abeni diff --git a/man/man8/ip-nexthop.8 b/man/man8/ip-nexthop.8 index 4d55f4db..f81a5910 100644 --- a/man/man8/ip-nexthop.8 +++ b/man/man8/ip-nexthop.8 @@ -28,6 +28,14 @@ ip-nexthop \- nexthop object management .BR "ip nexthop" " { " get " | " del " } id " .I ID +.ti -8 +.BI "ip nexthop bucket list " BUCKET_SELECTOR + +.ti -8 +.BR "ip nexthop bucket get " id +.I ID +.RI "index " INDEX + .ti -8 .IR SELECTOR " := " .RB "[ " id @@ -41,6 +49,12 @@ ip-nexthop \- nexthop object management .BR groups " ] [ " .BR fdb " ]" +.ti -8 +.IR BUCKET_SELECTOR " := " +.IR SELECTOR +.RB " | [ " nhid +.IR ID " ]" + .ti -8 .IR NH " := { " .BR blackhole " | [ " @@ -54,7 +68,9 @@ ip-nexthop \- nexthop object management .BR fdb " ] | " .B group .IR GROUP " [ " -.BR fdb " ] } " +.BR fdb " ] [ " +.B type +.IR TYPE " [ " TYPE_ARGS " ] ] }" .ti -8 .IR ENCAP " := [ " @@ -71,6 +87,23 @@ ip-nexthop \- nexthop object management .IR GROUP " := " .BR id "[," weight "[/...]" +.ti -8 +.IR TYPE " := { " +.BR mpath " | " resilient " }" + +.ti -8 +.IR TYPE_ARGS " := [ " +.IR RESILIENT_ARGS " ] " + +.ti -8 +.IR RESILIENT_ARGS " := " +.RB "[ " buckets +.IR BUCKETS " ] [ " +.B idle_timer +.IR IDLE " ] [ " +.B unbalanced_timer +.IR UNBALANCED " ]" + .SH DESCRIPTION .B ip nexthop is used to manipulate entries in the kernel's nexthop tables. @@ -122,9 +155,49 @@ is a set of encapsulation attributes specific to the .in -2 .TP -.BI group " GROUP" +.BI group " GROUP [ " type " TYPE [ TYPE_ARGS ] ]" create a nexthop group. Group specification is id with an optional weight (id,weight) and a '/' as a separator between entries. +.sp +.I TYPE +is a string specifying the nexthop group type. Namely: + +.in +8 +.BI mpath +- Multipath nexthop group backed by the hash-threshold algorithm. The +default when the type is unspecified. +.sp +.BI resilient +- Resilient nexthop group. Group is resilient to addition and deletion of +nexthops. + +.sp +.in -8 +.I TYPE_ARGS +is a set of attributes specific to the +.I TYPE. + +.in +8 +.B resilient +.in +2 +.B buckets +.I BUCKETS +- Number of nexthop buckets. Cannot be changed for an existing group +.sp + +.B idle_timer +.I IDLE +- Time in seconds in which a nexthop bucket does not see traffic and is +therefore considered idle. Default is 120 seconds + +.B unbalanced_timer +.I UNBALANCED +- Time in seconds in which a nexthop group is unbalanced and is therefore +considered unbalanced. The kernel will try to rebalance unbalanced groups, which +might result in some flows being reset. A value of 0 means that no +rebalancing will take place. Default is 0 seconds +.in -2 + .TP .B blackhole create a blackhole nexthop @@ -171,6 +244,37 @@ as show. ip nexthop get id ID get a single nexthop by id +.TP +ip nexthop bucket show +show the contents of the nexthop bucket table or the nexthop buckets +selected by some criteria. +.RS +.TP +.BI id " ID " +.in +0 +show the nexthop buckets that belong to a nexthop group with a given id +.TP +.BI nhid " ID " +.in +0 +show the nexthop buckets that hold a nexthop with a given id +.TP +.BI dev " DEV " +.in +0 +show the nexthop buckets using the given device +.TP +.BI vrf " NAME " +.in +0 +show the nexthop buckets using devices associated with the vrf name +.TP +.BI master " DEV " +.in +0 +show the nexthop buckets using devices enslaved to given master device +.RE + +.TP +ip nexthop bucket get id ID index INDEX +get a single nexthop bucket by nexthop group id and bucket index + .SH EXAMPLES .PP ip nexthop ls @@ -210,6 +314,11 @@ ip nexthop add id 7 group 5/6 fdb Adds a fdb nexthop group with id 7. A fdb nexthop group can only have fdb nexthops. .RE +.PP +ip nexthop add id 10 group 1/2 type resilient buckets 32 +.RS 4 +Add a resilient nexthop group with id 10 and 32 nexthop buckets. +.RE .SH SEE ALSO .br .BR ip (8) diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8 index 2669b386..003f6c3d 100644 --- a/man/man8/ip-xfrm.8 +++ b/man/man8/ip-xfrm.8 @@ -65,6 +65,8 @@ ip-xfrm \- transform configuration .IR MASK " ] ]" .RB "[ " if_id .IR IF-ID " ]" +.RB "[ " tfcpad +.IR LENGTH " ]" .ti -8 .B "ip xfrm state allocspi" diff --git a/man/man8/tc-police.8 b/man/man8/tc-police.8 index 52279755..86e263bb 100644 --- a/man/man8/tc-police.8 +++ b/man/man8/tc-police.8 @@ -5,9 +5,11 @@ police - policing action .SH SYNOPSIS .in +8 .ti -8 -.BR tc " ... " "action police" +.BR tc " ... " "action police [" .BI rate " RATE " burst -.IR BYTES [\fB/ BYTES "] [" +.IR BYTES [\fB/ BYTES "] ] [" +.BI pkts_rate " RATE " pkts_burst +.IR PACKETS "] [" .B mtu .IR BYTES [\fB/ BYTES "] ] [" .BI peakrate " RATE" @@ -34,19 +36,29 @@ police - policing action .SH DESCRIPTION The .B police -action allows to limit bandwidth of traffic matched by the filter it is -attached to. Basically there are two different algorithms available to measure -the packet rate: The first one uses an internal dual token bucket and is -configured using the +action allows limiting of the byte or packet rate of traffic matched by the +filter it is attached to. +.P +There are two different algorithms available to measure the byte rate: The +first one uses an internal dual token bucket and is configured using the .BR rate ", " burst ", " mtu ", " peakrate ", " overhead " and " linklayer parameters. The second one uses an in-kernel sampling mechanism. It can be fine-tuned using the .B estimator filter parameter. +.P +There is one algorithm available to measure packet rate and it is similar to +the first algorithm described for byte rate. It is configured using the +.BR pkt_rate " and " pkt_burst +parameters. +.P +At least one of the +.BR rate " and " pkt_rate " +parameters must be configured. .SH OPTIONS .TP .BI rate " RATE" -The maximum traffic rate of packets passing this action. Those exceeding it will +The maximum byte rate of packets passing this action. Those exceeding it will be treated as defined by the .B conform-exceed option. @@ -55,6 +67,15 @@ option. Set the maximum allowed burst in bytes, optionally followed by a slash ('/') sign and cell size which must be a power of 2. .TP +.BI pkt_rate " RATE" +The maximum packet rate or packets passing this action. Those exceeding it will +be treated as defined by the +.B conform-exceed +option. +.TP +.BI pkt_burst " PACKETS" +Set the maximum allowed burst in packets. +.TP .BI mtu " BYTES\fR[\fB/\fIBYTES\fR]" This is the maximum packet size handled by the policer (larger ones will be handled like they exceeded the configured rate). Setting this value correctly diff --git a/rdma/res.c b/rdma/res.c index dc12bbe4..f42ae938 100644 --- a/rdma/res.c +++ b/rdma/res.c @@ -195,30 +195,6 @@ void print_qp_type(struct rd *rd, uint32_t val) qp_types_to_str(val)); } -char *get_task_name(uint32_t pid) -{ - char *comm; - FILE *f; - - if (!pid) - return NULL; - - if (asprintf(&comm, "/proc/%d/comm", pid) < 0) - return NULL; - - f = fopen(comm, "r"); - free(comm); - if (!f) - return NULL; - - if (fscanf(f, "%ms\n", &comm) != 1) - comm = NULL; - - fclose(f); - - return comm; -} - void print_key(struct rd *rd, const char *name, uint64_t val, struct nlattr *nlattr) { diff --git a/rdma/res.h b/rdma/res.h index 707941da..e8bd02e4 100644 --- a/rdma/res.h +++ b/rdma/res.h @@ -155,7 +155,6 @@ filters qp_valid_filters[MAX_NUMBER_OF_FILTERS] = { 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); diff --git a/tc/m_police.c b/tc/m_police.c index bb51df68..9ef0e40b 100644 --- a/tc/m_police.c +++ b/tc/m_police.c @@ -38,7 +38,8 @@ struct action_util police_action_util = { static void usage(void) { fprintf(stderr, - "Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]\n" + "Usage: ... police [ rate BPS burst BYTES[/BYTES] ] \n" + " [ pkts_rate RATE pkts_burst PACKETS ] [ mtu BYTES[/BYTES] ]\n" " [ peakrate BPS ] [ avrate BPS ] [ overhead BYTES ]\n" " [ linklayer TYPE ] [ CONTROL ]\n" "Where: CONTROL := conform-exceed [/NOTEXCEEDACT]\n" @@ -67,6 +68,7 @@ static int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, int Rcell_log = -1, Pcell_log = -1; struct rtattr *tail; __u64 rate64 = 0, prate64 = 0; + __u64 pps64 = 0, ppsburst64 = 0; if (a) /* new way of doing things */ NEXT_ARG(); @@ -144,6 +146,18 @@ static int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p, NEXT_ARG(); if (get_linklayer(&linklayer, *argv)) invarg("linklayer", *argv); + } else if (matches(*argv, "pkts_rate") == 0) { + NEXT_ARG(); + if (pps64) + duparg("pkts_rate", *argv); + if (get_u64(&pps64, *argv, 10)) + invarg("pkts_rate", *argv); + } else if (matches(*argv, "pkts_burst") == 0) { + NEXT_ARG(); + if (ppsburst64) + duparg("pkts_burst", *argv); + if (get_u64(&ppsburst64, *argv, 10)) + invarg("pkts_burst", *argv); } else if (strcmp(*argv, "help") == 0) { usage(); } else { @@ -161,8 +175,8 @@ action_ctrl_ok: return -1; /* Must at least do late binding, use TB or ewma policing */ - if (!rate64 && !avrate && !p.index && !mtu) { - fprintf(stderr, "'rate' or 'avrate' or 'mtu' MUST be specified.\n"); + if (!rate64 && !avrate && !p.index && !mtu && !pps64) { + fprintf(stderr, "'rate' or 'avrate' or 'mtu' or 'pkts_rate' MUST be specified.\n"); return -1; } @@ -172,6 +186,18 @@ action_ctrl_ok: return -1; } + /* When the packets TB policer is used, pkts_burst is required */ + if (pps64 && !ppsburst64) { + fprintf(stderr, "'pkts_burst' requires 'pkts_rate'.\n"); + return -1; + } + + /* forbid rate and pkts_rate in same action */ + if (pps64 && rate64) { + fprintf(stderr, "'rate' and 'pkts_rate' are not allowed in same action.\n"); + return -1; + } + if (prate64) { if (!rate64) { fprintf(stderr, "'peakrate' requires 'rate'.\n"); @@ -223,6 +249,12 @@ action_ctrl_ok: if (presult) addattr32(n, MAX_MSG, TCA_POLICE_RESULT, presult); + if (pps64) { + addattr64(n, MAX_MSG, TCA_POLICE_PKTRATE64, pps64); + ppsburst64 = tc_calc_xmittime(pps64, ppsburst64); + addattr64(n, MAX_MSG, TCA_POLICE_PKTBURST64, ppsburst64); + } + addattr_nest_end(n, tail); res = 0; @@ -244,6 +276,7 @@ static int print_police(struct action_util *a, FILE *f, struct rtattr *arg) unsigned int buffer; unsigned int linklayer; __u64 rate64, prate64; + __u64 pps64, ppsburst64; if (arg == NULL) return 0; @@ -287,6 +320,17 @@ static int print_police(struct action_util *a, FILE *f, struct rtattr *arg) tc_print_rate(PRINT_FP, NULL, "avrate %s ", rta_getattr_u32(tb[TCA_POLICE_AVRATE])); + if ((tb[TCA_POLICE_PKTRATE64] && + RTA_PAYLOAD(tb[TCA_POLICE_PKTRATE64]) >= sizeof(pps64)) && + (tb[TCA_POLICE_PKTBURST64] && + RTA_PAYLOAD(tb[TCA_POLICE_PKTBURST64]) >= sizeof(ppsburst64))) { + pps64 = rta_getattr_u64(tb[TCA_POLICE_PKTRATE64]); + ppsburst64 = rta_getattr_u64(tb[TCA_POLICE_PKTBURST64]); + ppsburst64 = tc_calc_xmitsize(pps64, ppsburst64); + fprintf(f, "pkts_rate %llu ", pps64); + fprintf(f, "pkts_burst %llu ", ppsburst64); + } + print_action_control(f, "action ", p->action, ""); if (tb[TCA_POLICE_RESULT]) { diff --git a/tipc/bearer.c b/tipc/bearer.c index 4470819e..2afc48b9 100644 --- a/tipc/bearer.c +++ b/tipc/bearer.c @@ -21,9 +21,6 @@ #include #include -#include -#include - #include "utils.h" #include "cmdl.h" #include "msg.h" @@ -101,11 +98,11 @@ static int get_netid_cb(const struct nlmsghdr *nlh, void *data) static int generate_multicast(short af, char *buf, int bufsize) { - int netid; - char mnl_msg[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; + int netid; - if (!(nlh = msg_init(mnl_msg, TIPC_NL_NET_GET))) { + nlh = msg_init(TIPC_NL_NET_GET); + if (!nlh) { fprintf(stderr, "error, message initialization failed\n"); return -1; } @@ -399,7 +396,6 @@ static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd, { int err; char *media; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct opt *opt; struct nlattr *attrs; struct opt opts[] = { @@ -435,7 +431,8 @@ static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ADD))) { + nlh = msg_init(TIPC_NL_BEARER_ADD); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -482,7 +479,6 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, int err; struct opt *opt; struct nlattr *nest; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct opt opts[] = { { "device", OPT_KEYVAL, NULL }, { "domain", OPT_KEYVAL, NULL }, @@ -508,7 +504,8 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ENABLE))) { + nlh = msg_init(TIPC_NL_BEARER_ENABLE); + if (!nlh) { fprintf(stderr, "error: message initialisation failed\n"); return -1; } @@ -563,7 +560,6 @@ static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int err; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *nest; struct opt opts[] = { { "device", OPT_KEYVAL, NULL }, @@ -584,7 +580,8 @@ static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_BEARER_DISABLE))) { + nlh = msg_init(TIPC_NL_BEARER_DISABLE); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -628,7 +625,6 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, int err; int val; int prop; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *props; struct nlattr *attrs; struct opt opts[] = { @@ -675,7 +671,8 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, } } - if (!(nlh = msg_init(buf, TIPC_NL_BEARER_SET))) { + nlh = msg_init(TIPC_NL_BEARER_SET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -876,7 +873,6 @@ static int cmd_bearer_get_media(struct nlmsghdr *nlh, const struct cmd *cmd, { int err; char *media; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct opt *opt; struct cb_data cb_data = {0}; struct nlattr *attrs; @@ -918,7 +914,8 @@ static int cmd_bearer_get_media(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) { + nlh = msg_init(TIPC_NL_BEARER_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -956,7 +953,6 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, { int err; int prop; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *attrs; struct opt opts[] = { { "device", OPT_KEYVAL, NULL }, @@ -1001,7 +997,8 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, } } - if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) { + nlh = msg_init(TIPC_NL_BEARER_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -1056,14 +1053,13 @@ static int bearer_list_cb(const struct nlmsghdr *nlh, void *data) static int cmd_bearer_list(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - if (help_flag) { fprintf(stderr, "Usage: %s bearer list\n", cmdl->argv[0]); return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) { + nlh = msg_init(TIPC_NL_BEARER_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } diff --git a/tipc/cmdl.c b/tipc/cmdl.c index 981e268e..feaac2da 100644 --- a/tipc/cmdl.c +++ b/tipc/cmdl.c @@ -13,8 +13,6 @@ #include #include -#include - #include "cmdl.h" static const struct cmd *find_cmd(const struct cmd *cmds, char *str) diff --git a/tipc/link.c b/tipc/link.c index 192736ea..2123f109 100644 --- a/tipc/link.c +++ b/tipc/link.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "cmdl.h" #include "msg.h" @@ -60,7 +59,6 @@ static int link_list_cb(const struct nlmsghdr *nlh, void *data) static int cmd_link_list(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; int err = 0; if (help_flag) { @@ -68,7 +66,7 @@ static int cmd_link_list(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - nlh = msg_init(buf, TIPC_NL_LINK_GET); + nlh = msg_init(TIPC_NL_LINK_GET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -126,7 +124,6 @@ static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int prop; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *attrs; struct opt *opt; struct opt opts[] = { @@ -151,7 +148,7 @@ static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, if (parse_opts(opts, cmdl) < 0) return -EINVAL; - nlh = msg_init(buf, TIPC_NL_LINK_GET); + nlh = msg_init(TIPC_NL_LINK_GET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -241,7 +238,6 @@ static int cmd_link_get_bcast(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int prop = TIPC_NLA_PROP_BROADCAST; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *attrs; if (help_flag) { @@ -249,7 +245,7 @@ static int cmd_link_get_bcast(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - nlh = msg_init(buf, TIPC_NL_LINK_GET); + nlh = msg_init(TIPC_NL_LINK_GET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -284,7 +280,6 @@ static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { char *link; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct opt *opt; struct nlattr *nest; struct opt opts[] = { @@ -302,7 +297,7 @@ static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - nlh = msg_init(buf, TIPC_NL_LINK_RESET_STATS); + nlh = msg_init(TIPC_NL_LINK_RESET_STATS); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -550,7 +545,6 @@ static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { char *link = NULL; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct opt *opt; struct opt opts[] = { { "link", OPT_KEYVAL, NULL }, @@ -564,7 +558,7 @@ static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - nlh = msg_init(buf, TIPC_NL_LINK_GET); + nlh = msg_init(TIPC_NL_LINK_GET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -626,7 +620,6 @@ static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, { int val; int prop; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *props; struct nlattr *attrs; struct opt *opt; @@ -658,7 +651,7 @@ static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, if (parse_opts(opts, cmdl) < 0) return -EINVAL; - nlh = msg_init(buf, TIPC_NL_LINK_SET); + nlh = msg_init(TIPC_NL_LINK_SET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -704,7 +697,6 @@ static void cmd_link_set_bcast_help(struct cmdl *cmdl) static int cmd_link_set_bcast(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *props; struct nlattr *attrs; struct opt *opt; @@ -734,7 +726,7 @@ static int cmd_link_set_bcast(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - nlh = msg_init(buf, TIPC_NL_LINK_SET); + nlh = msg_init(TIPC_NL_LINK_SET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -788,7 +780,6 @@ static int cmd_link_mon_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int size; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *attrs; if (cmdl->argc != cmdl->optind + 1) { @@ -797,7 +788,7 @@ static int cmd_link_mon_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, } size = atoi(shift_cmdl(cmdl)); - nlh = msg_init(buf, TIPC_NL_MON_SET); + nlh = msg_init(TIPC_NL_MON_SET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -841,7 +832,6 @@ static int link_mon_summary_cb(const struct nlmsghdr *nlh, void *data) static int cmd_link_mon_summary(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; int err = 0; if (help_flag) { @@ -849,7 +839,7 @@ static int cmd_link_mon_summary(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - nlh = msg_init(buf, TIPC_NL_MON_GET); + nlh = msg_init(TIPC_NL_MON_GET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -1004,11 +994,10 @@ exit: static int link_mon_peer_list(uint32_t mon_ref) { struct nlmsghdr *nlh; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *nest; int err = 0; - nlh = msg_init(buf, TIPC_NL_MON_PEER_GET); + nlh = msg_init(TIPC_NL_MON_PEER_GET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -1080,7 +1069,6 @@ static void cmd_link_mon_list_udp_help(struct cmdl *cmdl, char *media) static int cmd_link_mon_list(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; char bname[TIPC_MAX_BEARER_NAME] = {0}; struct opt opts[] = { { "media", OPT_KEYVAL, NULL }, @@ -1112,7 +1100,7 @@ static int cmd_link_mon_list(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - nlh = msg_init(buf, TIPC_NL_MON_GET); + nlh = msg_init(TIPC_NL_MON_GET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -1176,9 +1164,8 @@ static int link_mon_get_cb(const struct nlmsghdr *nlh, void *data) static int cmd_link_mon_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - nlh = msg_init(buf, TIPC_NL_MON_GET); + nlh = msg_init(TIPC_NL_MON_GET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; diff --git a/tipc/media.c b/tipc/media.c index 969ef657..a3fec681 100644 --- a/tipc/media.c +++ b/tipc/media.c @@ -15,9 +15,7 @@ #include #include -#include #include -#include #include "cmdl.h" #include "msg.h" @@ -45,14 +43,13 @@ static int media_list_cb(const struct nlmsghdr *nlh, void *data) static int cmd_media_list(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - if (help_flag) { fprintf(stderr, "Usage: %s media list\n", cmdl->argv[0]); return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_MEDIA_GET))) { + nlh = msg_init(TIPC_NL_MEDIA_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -89,7 +86,6 @@ static int cmd_media_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int prop; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *nest; struct opt *opt; struct opt opts[] = { @@ -116,7 +112,8 @@ static int cmd_media_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, if (parse_opts(opts, cmdl) < 0) return -EINVAL; - if (!(nlh = msg_init(buf, TIPC_NL_MEDIA_GET))) { + nlh = msg_init(TIPC_NL_MEDIA_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -179,7 +176,6 @@ static int cmd_media_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, { int val; int prop; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *props; struct nlattr *attrs; struct opt *opt; @@ -213,7 +209,8 @@ static int cmd_media_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, if (parse_opts(opts, cmdl) < 0) return -EINVAL; - if (!(nlh = msg_init(buf, TIPC_NL_MEDIA_SET))) { + nlh = msg_init(TIPC_NL_MEDIA_SET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } diff --git a/tipc/msg.c b/tipc/msg.c index dc09d050..1225691c 100644 --- a/tipc/msg.c +++ b/tipc/msg.c @@ -13,13 +13,13 @@ #include #include -#include -#include -#include #include +#include "mnl_utils.h" #include "msg.h" +extern struct mnlu_gen_socket tipc_nlg; + int parse_attrs(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; @@ -30,141 +30,23 @@ int parse_attrs(const struct nlattr *attr, void *data) return MNL_CB_OK; } -static int family_id_cb(const struct nlmsghdr *nlh, void *data) -{ - struct nlattr *tb[CTRL_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - int *id = data; - - mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, tb); - if (!tb[CTRL_ATTR_FAMILY_ID]) - return MNL_CB_ERROR; - - *id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]); - - return MNL_CB_OK; -} - -static struct mnl_socket *msg_send(struct nlmsghdr *nlh) -{ - int ret; - struct mnl_socket *nl; - - nl = mnl_socket_open(NETLINK_GENERIC); - if (nl == NULL) { - perror("mnl_socket_open"); - return NULL; - } - - ret = mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID); - if (ret < 0) { - perror("mnl_socket_bind"); - return NULL; - } - - ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len); - if (ret < 0) { - perror("mnl_socket_send"); - return NULL; - } - - return nl; -} - -static int msg_recv(struct mnl_socket *nl, mnl_cb_t callback, void *data, int seq) -{ - int ret; - unsigned int portid; - char buf[MNL_SOCKET_BUFFER_SIZE]; - - portid = mnl_socket_get_portid(nl); - - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - while (ret > 0) { - ret = mnl_cb_run(buf, ret, seq, portid, callback, data); - if (ret <= 0) - break; - ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - } - if (ret == -1) - perror("error"); - - mnl_socket_close(nl); - - return ret; -} - -static int msg_query(struct nlmsghdr *nlh, mnl_cb_t callback, void *data) -{ - unsigned int seq; - struct mnl_socket *nl; - - seq = time(NULL); - nlh->nlmsg_seq = seq; - - nl = msg_send(nlh); - if (!nl) - return -ENOTSUP; - - return msg_recv(nl, callback, data, seq); -} - -static int get_family(void) -{ - int err; - int nl_family; - struct nlmsghdr *nlh; - struct genlmsghdr *genl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - - nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = GENL_ID_CTRL; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - - genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr)); - genl->cmd = CTRL_CMD_GETFAMILY; - genl->version = 1; - - mnl_attr_put_u16(nlh, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL); - mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, TIPC_GENL_V2_NAME); - - if ((err = msg_query(nlh, family_id_cb, &nl_family))) - return err; - - return nl_family; -} - int msg_doit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data) { nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - return msg_query(nlh, callback, data); + return mnlu_gen_socket_sndrcv(&tipc_nlg, nlh, callback, data); } int msg_dumpit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data) { nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - return msg_query(nlh, callback, data); + return mnlu_gen_socket_sndrcv(&tipc_nlg, nlh, callback, data); } -struct nlmsghdr *msg_init(char *buf, int cmd) +struct nlmsghdr *msg_init(int cmd) { - int family; struct nlmsghdr *nlh; - struct genlmsghdr *genl; - family = get_family(); - if (family <= 0) { - fprintf(stderr, - "Unable to get TIPC nl family id (module loaded?)\n"); - return NULL; - } - - nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = family; - - genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr)); - genl->cmd = cmd; - genl->version = 1; + nlh = mnlu_gen_socket_cmd_prepare(&tipc_nlg, cmd, 0); return nlh; } diff --git a/tipc/msg.h b/tipc/msg.h index 41fd1ad1..56af5a70 100644 --- a/tipc/msg.h +++ b/tipc/msg.h @@ -12,7 +12,7 @@ #ifndef _TIPC_MSG_H #define _TIPC_MSG_H -struct nlmsghdr *msg_init(char *buf, int cmd); +struct nlmsghdr *msg_init(int cmd); int msg_doit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data); int msg_dumpit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data); int parse_attrs(const struct nlattr *attr, void *data); diff --git a/tipc/nametable.c b/tipc/nametable.c index d899eeb6..b09ed5fc 100644 --- a/tipc/nametable.c +++ b/tipc/nametable.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "cmdl.h" #include "msg.h" @@ -82,7 +81,6 @@ static int cmd_nametable_show(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int iteration = 0; - char buf[MNL_SOCKET_BUFFER_SIZE]; int rc = 0; if (help_flag) { @@ -90,7 +88,8 @@ static int cmd_nametable_show(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_NAME_TABLE_GET))) { + nlh = msg_init(TIPC_NL_NAME_TABLE_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } diff --git a/tipc/node.c b/tipc/node.c index 05246013..ae75bfff 100644 --- a/tipc/node.c +++ b/tipc/node.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "cmdl.h" #include "msg.h" @@ -52,14 +51,13 @@ static int node_list_cb(const struct nlmsghdr *nlh, void *data) static int cmd_node_list(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - if (help_flag) { fprintf(stderr, "Usage: %s node list\n", cmdl->argv[0]); return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_NODE_GET))) { + nlh = msg_init(TIPC_NL_NODE_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -73,7 +71,6 @@ static int cmd_node_set_addr(struct nlmsghdr *nlh, const struct cmd *cmd, char *str; uint32_t addr; struct nlattr *nest; - char buf[MNL_SOCKET_BUFFER_SIZE]; if (cmdl->argc != cmdl->optind + 1) { fprintf(stderr, "Usage: %s node set address ADDRESS\n", @@ -86,7 +83,8 @@ static int cmd_node_set_addr(struct nlmsghdr *nlh, const struct cmd *cmd, if (!addr) return -1; - if (!(nlh = msg_init(buf, TIPC_NL_NET_SET))) { + nlh = msg_init(TIPC_NL_NET_SET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -126,7 +124,6 @@ static int cmd_node_get_addr(struct nlmsghdr *nlh, const struct cmd *cmd, static int cmd_node_set_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; uint8_t id[16] = {0,}; uint64_t *w0 = (uint64_t *) &id[0]; uint64_t *w1 = (uint64_t *) &id[8]; @@ -145,7 +142,7 @@ static int cmd_node_set_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - nlh = msg_init(buf, TIPC_NL_NET_SET); + nlh = msg_init(TIPC_NL_NET_SET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -201,7 +198,6 @@ static int cmd_node_set_key(struct nlmsghdr *nlh, const struct cmd *cmd, }; struct nlattr *nest; struct opt *opt_algname, *opt_nodeid, *opt_master, *opt_rekeying; - char buf[MNL_SOCKET_BUFFER_SIZE]; uint8_t id[TIPC_NODEID_LEN] = {0,}; uint32_t rekeying = 0; bool has_key = false; @@ -262,7 +258,7 @@ get_ops: } /* Init & do the command */ - nlh = msg_init(buf, TIPC_NL_KEY_SET); + nlh = msg_init(TIPC_NL_KEY_SET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -287,15 +283,13 @@ get_ops: static int cmd_node_flush_key(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - if (help_flag) { (cmd->help)(cmdl); return -EINVAL; } /* Init & do the command */ - nlh = msg_init(buf, TIPC_NL_KEY_FLUSH); + nlh = msg_init(TIPC_NL_KEY_FLUSH); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -332,14 +326,12 @@ static int nodeid_get_cb(const struct nlmsghdr *nlh, void *data) static int cmd_node_get_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - if (help_flag) { (cmd->help)(cmdl); return -EINVAL; } - nlh = msg_init(buf, TIPC_NL_NET_GET); + nlh = msg_init(TIPC_NL_NET_GET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; @@ -370,14 +362,13 @@ static int netid_get_cb(const struct nlmsghdr *nlh, void *data) static int cmd_node_get_netid(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - if (help_flag) { (cmd->help)(cmdl); return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_NET_GET))) { + nlh = msg_init(TIPC_NL_NET_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -389,7 +380,6 @@ static int cmd_node_set_netid(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int netid; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *nest; if (help_flag) { @@ -397,7 +387,8 @@ static int cmd_node_set_netid(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_NET_SET))) { + nlh = msg_init(TIPC_NL_NET_SET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } diff --git a/tipc/peer.c b/tipc/peer.c index f14ec35e..ed18efc5 100644 --- a/tipc/peer.c +++ b/tipc/peer.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "cmdl.h" #include "msg.h" @@ -30,7 +29,6 @@ static int cmd_peer_rm_addr(struct nlmsghdr *nlh, const struct cmd *cmd, char *str; uint32_t addr; struct nlattr *nest; - char buf[MNL_SOCKET_BUFFER_SIZE]; if ((cmdl->argc != cmdl->optind + 1) || help_flag) { fprintf(stderr, "Usage: %s peer remove address ADDRESS\n", @@ -47,7 +45,8 @@ static int cmd_peer_rm_addr(struct nlmsghdr *nlh, const struct cmd *cmd, if (!addr) return -1; - if (!(nlh = msg_init(buf, TIPC_NL_PEER_REMOVE))) { + nlh = msg_init(TIPC_NL_PEER_REMOVE); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -62,7 +61,6 @@ static int cmd_peer_rm_addr(struct nlmsghdr *nlh, const struct cmd *cmd, static int cmd_peer_rm_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; __u8 id[16] = {0,}; __u64 *w0 = (__u64 *)&id[0]; __u64 *w1 = (__u64 *)&id[8]; @@ -81,7 +79,7 @@ static int cmd_peer_rm_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; } - nlh = msg_init(buf, TIPC_NL_PEER_REMOVE); + nlh = msg_init(TIPC_NL_PEER_REMOVE); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; diff --git a/tipc/socket.c b/tipc/socket.c index 852984ec..deae12af 100644 --- a/tipc/socket.c +++ b/tipc/socket.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "cmdl.h" #include "msg.h" @@ -46,10 +45,10 @@ static int publ_list_cb(const struct nlmsghdr *nlh, void *data) static int publ_list(uint32_t sock) { struct nlmsghdr *nlh; - char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *nest; - if (!(nlh = msg_init(buf, TIPC_NL_PUBL_GET))) { + nlh = msg_init(TIPC_NL_PUBL_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } @@ -103,14 +102,13 @@ static int sock_list_cb(const struct nlmsghdr *nlh, void *data) static int cmd_socket_list(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - if (help_flag) { fprintf(stderr, "Usage: %s socket list\n", cmdl->argv[0]); return -EINVAL; } - if (!(nlh = msg_init(buf, TIPC_NL_SOCK_GET))) { + nlh = msg_init(TIPC_NL_SOCK_GET); + if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } diff --git a/tipc/tipc.c b/tipc/tipc.c index 60176a04..9f23a4bf 100644 --- a/tipc/tipc.c +++ b/tipc/tipc.c @@ -13,7 +13,11 @@ #include #include #include +#include +#include +#include +#include "mnl_utils.h" #include "bearer.h" #include "link.h" #include "nametable.h" @@ -26,6 +30,7 @@ int help_flag; int json; +struct mnlu_gen_socket tipc_nlg; static void about(struct cmdl *cmdl) { @@ -110,8 +115,20 @@ int main(int argc, char *argv[]) cmdl.argc = argc; cmdl.argv = argv; - if ((res = run_cmd(NULL, &cmd, cmds, &cmdl, NULL)) != 0) - return 1; + res = mnlu_gen_socket_open(&tipc_nlg, TIPC_GENL_V2_NAME, + TIPC_GENL_V2_VERSION); + if (res) { + fprintf(stderr, + "Unable to get TIPC nl family id (module loaded?)\n"); + return -1; + } + res = run_cmd(NULL, &cmd, cmds, &cmdl, &tipc_nlg); + if (res != 0) { + mnlu_gen_socket_close(&tipc_nlg); + return -1; + } + + mnlu_gen_socket_close(&tipc_nlg); return 0; }