It was noticed that quite a lot of functions create their own netlink socket just to talk to batman-adv. This is related to the old sysfs compat code which was removed in 2021.0. So restructure the code to make use of the existing global information in the state object.
Kind regards, Sven
Sven Eckelmann (6): batctl: Consume genl ACKs after setting reads batctl: throughputmeter: Use global genl socket batctl: interface: List using shared genl socket batctl: Get meshif info using shared genl socket batctl: Use common genl socket for netlink_query_common batctl: routing_algo: List using shared genl socket
functions.c | 15 +++--- functions.h | 5 +- gateways.c | 3 +- gw_mode.c | 3 +- icmp_helper.c | 14 +++--- icmp_helper.h | 2 +- interface.c | 77 ++++++++++++----------------- mcast_flags.c | 3 +- netlink.c | 121 +++++++++++++++++----------------------------- netlink.h | 12 ++--- originators.c | 3 +- ping.c | 7 +-- routing_algo.c | 74 +++++++++++++--------------- sys.c | 8 ++- throughputmeter.c | 105 ++++++++-------------------------------- traceroute.c | 7 +-- translate.c | 5 +- 17 files changed, 176 insertions(+), 288 deletions(-)
The kernel is sending an ACK after an successful read request via the batadv genl socket. This ack must be consumed manually after the actual message was processed. Otherwise, the next user of the socket can get confused by the unexpected ACK in the socket queue.
Signed-off-by: Sven Eckelmann sven@narfation.org --- sys.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/sys.c b/sys.c index 6dd8c10..f1dc275 100644 --- a/sys.c +++ b/sys.c @@ -107,7 +107,13 @@ int sys_simple_nlquery(struct state *state, enum batadv_nl_commands nl_cmd, nl_send_auto_complete(state->sock, msg); nlmsg_free(msg);
- nl_recvmsgs(state->sock, state->cb); + if (callback) { + ret = nl_recvmsgs(state->sock, state->cb); + if (ret < 0) + return ret; + } + + nl_wait_for_ack(state->sock);
return result; }
The batctl framework can take care of creating the netlink socket and gathering the data for a mesh interface. It is not necessary to duplicate all the code to create, setup and destroy the batadv genl socket for a standard socket.
Signed-off-by: Sven Eckelmann sven@narfation.org --- throughputmeter.c | 105 ++++++++++------------------------------------ 1 file changed, 21 insertions(+), 84 deletions(-)
diff --git a/throughputmeter.c b/throughputmeter.c index f50f521..7f89651 100644 --- a/throughputmeter.c +++ b/throughputmeter.c @@ -34,7 +34,7 @@ #include "netlink.h"
static struct ether_addr *dst_mac; -static char *tp_mesh_iface; +static struct state *tp_state;
struct tp_result { int error; @@ -151,62 +151,34 @@ static int tp_meter_cookie_callback(struct nl_msg *msg, void *arg) return NL_OK; }
-static int tp_meter_start(char *mesh_iface, struct ether_addr *dst_mac, + +static int tp_meter_start(struct state *state, struct ether_addr *dst_mac, uint32_t time, struct tp_cookie *cookie) { - struct nl_sock *sock; struct nl_msg *msg; struct nl_cb *cb; - int ifindex; - int family; - int ret; int err = 0;
- sock = nl_socket_alloc(); - if (!sock) - return -ENOMEM; - - ret = genl_connect(sock); - if (ret < 0) { - err = -EOPNOTSUPP; - goto out; - } - - family = genl_ctrl_resolve(sock, BATADV_NL_NAME); - if (family < 0) { - err = -EOPNOTSUPP; - goto out; - } - - ifindex = if_nametoindex(mesh_iface); - if (!ifindex) { - fprintf(stderr, "Interface %s is unknown\n", mesh_iface); - err = -ENODEV; - goto out; - } - cb = nl_cb_alloc(NL_CB_DEFAULT); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, tp_meter_cookie_callback, cookie); nl_cb_err(cb, NL_CB_CUSTOM, tpmeter_nl_print_error, cookie);
msg = nlmsg_alloc(); - if (!msg) { - err = -ENOMEM; - goto out; - } + if (!msg) + return -ENOMEM;
- genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, state->batadv_family, 0, 0, BATADV_CMD_TP_METER, 1);
- nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex); + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, state->mesh_ifindex); nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, dst_mac); nla_put_u32(msg, BATADV_ATTR_TPMETER_TEST_TIME, time);
- nl_send_auto_complete(sock, msg); + nl_send_auto_complete(state->sock, msg); nlmsg_free(msg);
- nl_recvmsgs(sock, cb); + nl_recvmsgs(state->sock, cb);
nl_cb_put(cb);
@@ -215,9 +187,6 @@ static int tp_meter_start(char *mesh_iface, struct ether_addr *dst_mac, else if (!cookie->found) err= -EINVAL;
-out: - nl_socket_free(sock); - return err; }
@@ -251,57 +220,24 @@ static int tp_recv_result(struct nl_sock *sock, struct tp_result *result) return err; }
-static int tp_meter_stop(char *mesh_iface, struct ether_addr *dst_mac) +static int tp_meter_stop(struct state *state, struct ether_addr *dst_mac) { - struct nl_sock *sock; struct nl_msg *msg; - int ifindex; - int family; - int ret; - int err = 0; - - sock = nl_socket_alloc(); - if (!sock) - return -ENOMEM; - - ret = genl_connect(sock); - if (ret < 0) { - err = -EOPNOTSUPP; - goto out; - } - - family = genl_ctrl_resolve(sock, BATADV_NL_NAME); - if (family < 0) { - err = -EOPNOTSUPP; - goto out; - } - - ifindex = if_nametoindex(mesh_iface); - if (!ifindex) { - fprintf(stderr, "Interface %s is unknown\n", mesh_iface); - err = -ENODEV; - goto out; - }
msg = nlmsg_alloc(); - if (!msg) { - err = -ENOMEM; - goto out; - } + if (!msg) + return -ENOMEM;
- genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, state->batadv_family, 0, 0, BATADV_CMD_TP_METER_CANCEL, 1);
- nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex); + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, state->mesh_ifindex); nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, dst_mac);
- nl_send_auto_complete(sock, msg); + nl_send_auto_complete(state->sock, msg); nlmsg_free(msg);
-out: - nl_socket_free(sock); - - return err; + return 0; }
static struct nl_sock *tp_prepare_listening_sock(void) @@ -358,7 +294,7 @@ void tp_sig_handler(int sig) case SIGINT: case SIGTERM: fflush(stdout); - tp_meter_stop(tp_mesh_iface, dst_mac); + tp_meter_stop(tp_state, dst_mac); break; default: break; @@ -443,7 +379,7 @@ static int throughputmeter(struct state *state, int argc, char **argv) dst_string = ether_ntoa_long(dst_mac);
/* for sighandler */ - tp_mesh_iface = state->mesh_iface; + tp_state = state; signal(SIGINT, tp_sig_handler); signal(SIGTERM, tp_sig_handler);
@@ -451,7 +387,7 @@ static int throughputmeter(struct state *state, int argc, char **argv) if (!listen_sock) goto out;
- ret = tp_meter_start(state->mesh_iface, dst_mac, time, &cookie); + ret = tp_meter_start(state, dst_mac, time, &cookie); if (ret < 0) { printf("Failed to send tp_meter request to kernel: %d\n", ret); goto out; @@ -529,5 +465,6 @@ static int throughputmeter(struct state *state, int argc, char **argv) return ret; }
-COMMAND(SUBCOMMAND_MIF, throughputmeter, "tp", COMMAND_FLAG_MESH_IFACE, NULL, +COMMAND(SUBCOMMAND_MIF, throughputmeter, "tp", + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, NULL, "<destination> \tstart a throughput measurement");
The interface subcommand doesn't need to allocate a new netlink socket to query the state of a single interface. But it can also not use the socket which is automatically pre-configured by COMMAND_FLAG_NETLINK because the (main sub)command might also be started for interfaces which might not exist yet.
Instead use the shared functions to pre-allocate the necessary state information when calling the "list" sub-subcommand.
Signed-off-by: Sven Eckelmann sven@narfation.org --- interface.c | 77 +++++++++++++++++++++-------------------------------- 1 file changed, 31 insertions(+), 46 deletions(-)
diff --git a/interface.c b/interface.c index cf9c0c3..a96a328 100644 --- a/interface.c +++ b/interface.c @@ -62,65 +62,46 @@ static int get_iface_status_netlink_parse(struct nl_msg *msg, void *arg)
iface_status[IFACE_STATUS_LEN - 1] = '\0';
- return NL_STOP; + return NL_OK; }
-static char *get_iface_status_netlink(unsigned int meshif, unsigned int hardif, +static char *get_iface_status_netlink(struct state *state, unsigned int hardif, char *iface_status) { char *ret_status = NULL; - struct nl_sock *sock; struct nl_msg *msg; - int batadv_family; - struct nl_cb *cb; int ret;
iface_status[0] = '\0';
- sock = nl_socket_alloc(); - if (!sock) - return NULL; - - ret = genl_connect(sock); - if (ret < 0) - goto err_free_sock; - - batadv_family = genl_ctrl_resolve(sock, BATADV_NL_NAME); - if (batadv_family < 0) - goto err_free_sock; - - cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!cb) - goto err_free_sock; - - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_status_netlink_parse, + nl_cb_set(state->cb, NL_CB_VALID, NL_CB_CUSTOM, get_iface_status_netlink_parse, iface_status);
msg = nlmsg_alloc(); if (!msg) - goto err_free_cb; + return NULL;
- genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, batadv_family, + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, state->batadv_family, 0, 0, BATADV_CMD_GET_HARDIF, 1);
- nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, meshif); + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, state->mesh_ifindex); nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX, hardif);
- ret = nl_send_auto_complete(sock, msg); + ret = nl_send_auto_complete(state->sock, msg); + if (ret < 0) + goto err_free_msg; + + ret = nl_recvmsgs(state->sock, state->cb); if (ret < 0) goto err_free_msg;
- nl_recvmsgs(sock, cb); + nl_wait_for_ack(state->sock);
if (strlen(iface_status) > 0) ret_status = iface_status;
err_free_msg: nlmsg_free(msg); -err_free_cb: - nl_cb_put(cb); -err_free_sock: - nl_socket_free(sock);
return ret_status; } @@ -130,20 +111,16 @@ static struct nla_policy link_policy[IFLA_MAX + 1] = { [IFLA_MASTER] = { .type = NLA_U32 }, };
-struct print_interfaces_rtnl_arg { - int ifindex; -}; - static int print_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) { - struct print_interfaces_rtnl_arg *print_arg = arg; char iface_status[IFACE_STATUS_LEN]; struct nlattr *attrs[IFLA_MAX + 1]; + struct state *state = arg; struct ifinfomsg *ifm; + unsigned int master; char *ifname; int ret; const char *status; - int master;
ifm = nlmsg_data(nlmsg_hdr(msg)); ret = nlmsg_parse(nlmsg_hdr(msg), sizeof(*ifm), attrs, IFLA_MAX, @@ -161,10 +138,10 @@ static int print_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) master = nla_get_u32(attrs[IFLA_MASTER]);
/* required on older kernels which don't prefilter the results */ - if (master != print_arg->ifindex) + if (master != state->mesh_ifindex) goto err;
- status = get_iface_status_netlink(master, ifm->ifi_index, iface_status); + status = get_iface_status_netlink(state, ifm->ifi_index, iface_status); if (!status) status = "<error reading status>\n";
@@ -174,21 +151,29 @@ static int print_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) return NL_OK; }
-static int print_interfaces(char *mesh_iface) +static int print_interfaces(struct state *state) { - struct print_interfaces_rtnl_arg print_arg; + int ret;
if (!file_exists(module_ver_path)) { fprintf(stderr, "Error - batman-adv module has not been loaded\n"); return EXIT_FAILURE; }
- print_arg.ifindex = if_nametoindex(mesh_iface); - if (!print_arg.ifindex) + /* duplicated code here from the main() because interface doesn't always + * need COMMAND_FLAG_MESH_IFACE and COMMAND_FLAG_NETLINK + */ + if (check_mesh_iface(state)) return EXIT_FAILURE;
- query_rtnl_link(print_arg.ifindex, print_interfaces_rtnl_parse, - &print_arg); + ret = netlink_create(state); + if (ret < 0) + return EXIT_FAILURE; + + query_rtnl_link(state->mesh_ifindex, print_interfaces_rtnl_parse, + state); + + netlink_destroy(state);
return EXIT_SUCCESS; } @@ -452,7 +437,7 @@ static int interface(struct state *state, int argc, char **argv) rest_argv = &argv[optind];
if (rest_argc == 0) - return print_interfaces(state->mesh_iface); + return print_interfaces(state);
check_root_or_die("batctl interface");
All subcommands which are using the netlink_get_info helper are already creating state object with batadv genl socket. It is not necessary to create a new one just to request data from the kernel.
Signed-off-by: Sven Eckelmann sven@narfation.org --- gateways.c | 3 +-- mcast_flags.c | 3 +-- netlink.c | 40 +++++++++++++--------------------------- netlink.h | 2 +- originators.c | 3 +-- 5 files changed, 17 insertions(+), 34 deletions(-)
diff --git a/gateways.c b/gateways.c index 7625bd8..bdd6795 100644 --- a/gateways.c +++ b/gateways.c @@ -122,8 +122,7 @@ static int netlink_print_gateways(struct state *state, char *orig_iface,
/* only parse routing algorithm name */ last_err = -EINVAL; - info_header = netlink_get_info(state->mesh_ifindex, - BATADV_CMD_GET_ORIGINATORS, NULL); + info_header = netlink_get_info(state, BATADV_CMD_GET_ORIGINATORS, NULL); free(info_header);
if (strlen(algo_name_buf) == 0) diff --git a/mcast_flags.c b/mcast_flags.c index 721f549..44344e0 100644 --- a/mcast_flags.c +++ b/mcast_flags.c @@ -104,8 +104,7 @@ static int netlink_print_mcast_flags(struct state *state, char *orig_iface, int ret;
/* only parse own multicast flags */ - info_header = netlink_get_info(state->mesh_ifindex, - BATADV_CMD_GET_MCAST_FLAGS, NULL); + info_header = netlink_get_info(state, BATADV_CMD_GET_MCAST_FLAGS, NULL); free(info_header);
if (mcast_flags == -EOPNOTSUPP || mcast_flags_priv == -EOPNOTSUPP) diff --git a/netlink.c b/netlink.c index 31c9b01..e3a7b7c 100644 --- a/netlink.c +++ b/netlink.c @@ -339,60 +339,46 @@ static int info_callback(struct nl_msg *msg, void *arg) opts->remaining_header = NULL; }
- return NL_STOP; + return NL_OK; }
-char *netlink_get_info(int ifindex, uint8_t nl_cmd, const char *header) +char *netlink_get_info(struct state *state, uint8_t nl_cmd, const char *header) { - struct nl_sock *sock; struct nl_msg *msg; struct nl_cb *cb; - int family; struct print_opts opts = { .read_opt = 0, .nl_cmd = nl_cmd, .remaining_header = NULL, .static_header = header, }; - - sock = nl_socket_alloc(); - if (!sock) - return NULL; - - genl_connect(sock); - - family = genl_ctrl_resolve(sock, BATADV_NL_NAME); - if (family < 0) { - nl_socket_free(sock); - return NULL; - } + int ret;
msg = nlmsg_alloc(); - if (!msg) { - nl_socket_free(sock); + if (!msg) return NULL; - }
- genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, 0, + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, state->batadv_family, 0, 0, BATADV_CMD_GET_MESH_INFO, 1);
- nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex); + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, state->mesh_ifindex);
- nl_send_auto_complete(sock, msg); + nl_send_auto_complete(state->sock, msg);
nlmsg_free(msg);
cb = nl_cb_alloc(NL_CB_DEFAULT); if (!cb) - goto err_free_sock; + return NULL;
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, info_callback, &opts); nl_cb_err(cb, NL_CB_CUSTOM, netlink_print_error, NULL);
- nl_recvmsgs(sock, cb); + ret = nl_recvmsgs(state->sock, cb); + if (ret < 0) + return opts.remaining_header;
-err_free_sock: - nl_socket_free(sock); + nl_wait_for_ack(state->sock);
return opts.remaining_header; } @@ -458,7 +444,7 @@ int netlink_print_common(struct state *state, char *orig_iface, int read_opt, printf("\033[2J\033[0;0f");
if (!(read_opt & SKIP_HEADER)) - opts.remaining_header = netlink_get_info(state->mesh_ifindex, + opts.remaining_header = netlink_get_info(state, nl_cmd, header);
diff --git a/netlink.h b/netlink.h index 4ee2f39..48a2a23 100644 --- a/netlink.h +++ b/netlink.h @@ -30,7 +30,7 @@ struct ether_addr; int netlink_create(struct state *state); void netlink_destroy(struct state *state);
-char *netlink_get_info(int ifindex, uint8_t nl_cmd, const char *header); +char *netlink_get_info(struct state *state, uint8_t nl_cmd, const char *header); int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac, struct ether_addr *mac_out); int get_nexthop_netlink(const char *mesh_iface, const struct ether_addr *mac, diff --git a/originators.c b/originators.c index 8a29dd7..a8b313e 100644 --- a/originators.c +++ b/originators.c @@ -174,8 +174,7 @@ static int netlink_print_originators(struct state *state, char *orig_iface,
/* only parse routing algorithm name */ last_err = -EINVAL; - info_header = netlink_get_info(state->mesh_ifindex, - BATADV_CMD_GET_ORIGINATORS, NULL); + info_header = netlink_get_info(state, BATADV_CMD_GET_ORIGINATORS, NULL); free(info_header);
if (strlen(algo_name_buf) == 0)
All functions which use the netlink_query_common can be changed to provide the socket for batadv genl operations in the state object. Either by manually calling netlink_create or by simply using the COMMAND_FLAG_NETLINK.
This makes is unnecessary to allocate a new netlink socket and resolve the generic netlink family for each helper function call.
Signed-off-by: Sven Eckelmann sven@narfation.org --- functions.c | 15 +++++----- functions.h | 5 ++-- gw_mode.c | 3 +- icmp_helper.c | 14 ++++----- icmp_helper.h | 2 +- netlink.c | 81 +++++++++++++++++++------------------------------- netlink.h | 10 +++---- ping.c | 7 +++-- routing_algo.c | 23 ++++++++++---- traceroute.c | 7 +++-- translate.c | 5 ++-- 11 files changed, 84 insertions(+), 88 deletions(-)
diff --git a/functions.c b/functions.c index 0dbf2ed..617fc5b 100644 --- a/functions.c +++ b/functions.c @@ -171,7 +171,7 @@ int read_file(const char *full_path, int read_opt) return res; }
-struct ether_addr *translate_mac(const char *mesh_iface, +struct ether_addr *translate_mac(struct state *state, const struct ether_addr *mac) { struct ether_addr in_mac; @@ -188,14 +188,16 @@ struct ether_addr *translate_mac(const char *mesh_iface, if (!ether_addr_valid(in_mac.ether_addr_octet)) return mac_result;
- translate_mac_netlink(mesh_iface, &in_mac, mac_result); + translate_mac_netlink(state, &in_mac, mac_result);
return mac_result; }
-int get_algoname(const char *mesh_iface, char *algoname, size_t algoname_len) +int get_algoname(struct state *state, unsigned int mesh_ifindex, + char *algoname, size_t algoname_len) { - return get_algoname_netlink(mesh_iface, algoname, algoname_len); + return get_algoname_netlink(state, mesh_ifindex, algoname, + algoname_len); }
static int resolve_l3addr(int ai_family, const char *asc, void *l3addr) @@ -340,10 +342,7 @@ static int resolve_mac_from_parse(struct nl_msg *msg, void *arg) }
err: - if (nl_arg->found) - return NL_STOP; - else - return NL_OK; + return NL_OK; }
static struct ether_addr *resolve_mac_from_cache(int ai_family, diff --git a/functions.h b/functions.h index 3bb66f6..860d9f4 100644 --- a/functions.h +++ b/functions.h @@ -44,7 +44,7 @@ char *get_name_by_macaddr(struct ether_addr *mac_addr, int read_opt); char *get_name_by_macstr(char *mac_str, int read_opt); int file_exists(const char *fpath); int read_file(const char *full_path, int read_opt); -struct ether_addr *translate_mac(const char *mesh_iface, +struct ether_addr *translate_mac(struct state *state, const struct ether_addr *mac); struct ether_addr *resolve_mac(const char *asc); int query_rtnl_link(int ifindex, nl_recvmsg_msg_cb_t func, void *arg); @@ -54,7 +54,8 @@ int translate_vlan_iface(struct state *state, const char *vlandev); int translate_vid(struct state *state, const char *vidstr); int translate_hard_iface(struct state *state, const char *hardif); int guess_netdev_type(const char *netdev, enum selector_prefix *type); -int get_algoname(const char *mesh_iface, char *algoname, size_t algoname_len); +int get_algoname(struct state *state, unsigned int mesh_ifindex, + char *algoname, size_t algoname_len); int check_mesh_iface(struct state *state); int check_mesh_iface_ownership(struct state *state, char *hard_iface);
diff --git a/gw_mode.c b/gw_mode.c index 0bc99e2..93f255c 100644 --- a/gw_mode.c +++ b/gw_mode.c @@ -46,7 +46,8 @@ static bool is_throughput_select_class(struct state *state) char algoname[32]; int ret;
- ret = get_algoname(state->mesh_iface, algoname, sizeof(algoname)); + ret = get_algoname(state, state->mesh_ifindex, algoname, + sizeof(algoname));
/* no algo name -> assume that it is a pre-B.A.T.M.A.N. V version */ if (ret < 0) diff --git a/icmp_helper.c b/icmp_helper.c index 3aa49c0..cbb6122 100644 --- a/icmp_helper.c +++ b/icmp_helper.c @@ -314,13 +314,11 @@ static void icmp_interface_sweep(void) } }
-static int icmp_interface_update(const char *mesh_iface) +static int icmp_interface_update(struct state *state) { struct icmp_interface_update_arg update_arg;
- update_arg.ifindex = if_nametoindex(mesh_iface); - if (!update_arg.ifindex) - return -errno; + update_arg.ifindex = state->mesh_ifindex;
/* unmark current interface - will be marked again by query */ icmp_interface_unmark(); @@ -331,7 +329,7 @@ static int icmp_interface_update(const char *mesh_iface) /* remove old interfaces */ icmp_interface_sweep();
- get_primarymac_netlink(mesh_iface, primary_mac); + get_primarymac_netlink(state, primary_mac);
return 0; } @@ -355,7 +353,7 @@ static int icmp_interface_send(struct batadv_icmp_header *icmp_packet, return (int)writev(iface->sock, vector, 2); }
-int icmp_interface_write(const char *mesh_iface, +int icmp_interface_write(struct state *state, struct batadv_icmp_header *icmp_packet, size_t len) { struct batadv_icmp_packet_rr *icmp_packet_rr; @@ -380,7 +378,7 @@ int icmp_interface_write(const char *mesh_iface, if (icmp_packet->msg_type != BATADV_ECHO_REQUEST) return -EINVAL;
- icmp_interface_update(mesh_iface); + icmp_interface_update(state);
if (list_empty(&interface_list)) return -EFAULT; @@ -388,7 +386,7 @@ int icmp_interface_write(const char *mesh_iface, /* find best neighbor */ memcpy(&mac, icmp_packet->dst, ETH_ALEN);
- ret = get_nexthop_netlink(mesh_iface, &mac, nexthop, ifname); + ret = get_nexthop_netlink(state, &mac, nexthop, ifname); if (ret < 0) goto dst_unreachable;
diff --git a/icmp_helper.h b/icmp_helper.h index 6f84d34..5eed55e 100644 --- a/icmp_helper.h +++ b/icmp_helper.h @@ -35,7 +35,7 @@ struct icmp_interface { };
int icmp_interfaces_init(void); -int icmp_interface_write(const char *mesh_iface, +int icmp_interface_write(struct state *state, struct batadv_icmp_header *icmp_packet, size_t len); void icmp_interfaces_clean(void); ssize_t icmp_interface_read(struct batadv_icmp_header *icmp_packet, size_t len, diff --git a/netlink.c b/netlink.c index e3a7b7c..b8bca30 100644 --- a/netlink.c +++ b/netlink.c @@ -503,46 +503,20 @@ static int nlquery_stop_cb(struct nl_msg *msg, void *arg) return NL_STOP; }
-static int netlink_query_common(const char *mesh_iface, uint8_t nl_cmd, +static int netlink_query_common(struct state *state, + unsigned int mesh_ifindex, uint8_t nl_cmd, nl_recvmsg_msg_cb_t callback, int flags, struct nlquery_opts *query_opts) { - struct nl_sock *sock; struct nl_msg *msg; struct nl_cb *cb; - int ifindex; - int family; int ret;
query_opts->err = 0;
- sock = nl_socket_alloc(); - if (!sock) - return -ENOMEM; - - ret = genl_connect(sock); - if (ret < 0) { - query_opts->err = ret; - goto err_free_sock; - } - - family = genl_ctrl_resolve(sock, BATADV_NL_NAME); - if (family < 0) { - query_opts->err = -EOPNOTSUPP; - goto err_free_sock; - } - - ifindex = if_nametoindex(mesh_iface); - if (!ifindex) { - query_opts->err = -ENODEV; - goto err_free_sock; - } - cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!cb) { - query_opts->err = -ENOMEM; - goto err_free_sock; - } + if (!cb) + return -ENOMEM;
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, callback, query_opts); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nlquery_stop_cb, query_opts); @@ -554,19 +528,24 @@ static int netlink_query_common(const char *mesh_iface, uint8_t nl_cmd, goto err_free_cb; }
- genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, flags, - nl_cmd, 1); + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, state->batadv_family, 0, + flags, nl_cmd, 1);
- nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, ifindex); - nl_send_auto_complete(sock, msg); + nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, mesh_ifindex); + nl_send_auto_complete(state->sock, msg); nlmsg_free(msg);
- nl_recvmsgs(sock, cb); + ret = nl_recvmsgs(state->sock, cb); + if (ret < 0) { + query_opts->err = ret; + goto err_free_cb; + } + + if (!(flags & NLM_F_DUMP)) + nl_wait_for_ack(state->sock);
err_free_cb: nl_cb_put(cb); -err_free_sock: - nl_socket_free(sock);
return query_opts->err; } @@ -625,10 +604,10 @@ static int translate_mac_netlink_cb(struct nl_msg *msg, void *arg) opts->found = true; opts->query_opts.err = 0;
- return NL_STOP; + return NL_OK; }
-int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac, +int translate_mac_netlink(struct state *state, const struct ether_addr *mac, struct ether_addr *mac_out) { struct translate_mac_netlink_opts opts = { @@ -641,7 +620,7 @@ int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac,
memcpy(&opts.mac, mac, ETH_ALEN);
- ret = netlink_query_common(mesh_iface, + ret = netlink_query_common(state, state->mesh_ifindex, BATADV_CMD_GET_TRANSTABLE_GLOBAL, translate_mac_netlink_cb, NLM_F_DUMP, &opts.query_opts); @@ -721,10 +700,10 @@ static int get_nexthop_netlink_cb(struct nl_msg *msg, void *arg) opts->found = true; opts->query_opts.err = 0;
- return NL_STOP; + return NL_OK; }
-int get_nexthop_netlink(const char *mesh_iface, const struct ether_addr *mac, +int get_nexthop_netlink(struct state *state, const struct ether_addr *mac, uint8_t *nexthop, char *ifname) { struct get_nexthop_netlink_opts opts = { @@ -740,7 +719,8 @@ int get_nexthop_netlink(const char *mesh_iface, const struct ether_addr *mac, opts.nexthop = nexthop; opts.ifname = ifname;
- ret = netlink_query_common(mesh_iface, BATADV_CMD_GET_ORIGINATORS, + ret = netlink_query_common(state, state->mesh_ifindex, + BATADV_CMD_GET_ORIGINATORS, get_nexthop_netlink_cb, NLM_F_DUMP, &opts.query_opts); if (ret < 0) @@ -799,10 +779,10 @@ static int get_primarymac_netlink_cb(struct nl_msg *msg, void *arg) opts->found = true; opts->query_opts.err = 0;
- return NL_STOP; + return NL_OK; }
-int get_primarymac_netlink(const char *mesh_iface, uint8_t *primarymac) +int get_primarymac_netlink(struct state *state, uint8_t *primarymac) { struct get_primarymac_netlink_opts opts = { .primarymac = 0, @@ -815,7 +795,8 @@ int get_primarymac_netlink(const char *mesh_iface, uint8_t *primarymac)
opts.primarymac = primarymac;
- ret = netlink_query_common(mesh_iface, BATADV_CMD_GET_MESH_INFO, + ret = netlink_query_common(state, state->mesh_ifindex, + BATADV_CMD_GET_MESH_INFO, get_primarymac_netlink_cb, 0, &opts.query_opts); if (ret < 0) @@ -875,11 +856,11 @@ static int get_algoname_netlink_cb(struct nl_msg *msg, void *arg) opts->found = true; opts->query_opts.err = 0;
- return NL_STOP; + return NL_OK; }
-int get_algoname_netlink(const char *mesh_iface, char *algoname, - size_t algoname_len) +int get_algoname_netlink(struct state *state, unsigned int mesh_ifindex, + char *algoname, size_t algoname_len) { struct get_algoname_netlink_opts opts = { .algoname = algoname, @@ -891,7 +872,7 @@ int get_algoname_netlink(const char *mesh_iface, char *algoname, }; int ret;
- ret = netlink_query_common(mesh_iface, BATADV_CMD_GET_MESH, + ret = netlink_query_common(state, mesh_ifindex, BATADV_CMD_GET_MESH, get_algoname_netlink_cb, 0, &opts.query_opts); if (ret < 0) diff --git a/netlink.h b/netlink.h index 48a2a23..2cc5862 100644 --- a/netlink.h +++ b/netlink.h @@ -31,13 +31,13 @@ int netlink_create(struct state *state); void netlink_destroy(struct state *state);
char *netlink_get_info(struct state *state, uint8_t nl_cmd, const char *header); -int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac, +int translate_mac_netlink(struct state *state, const struct ether_addr *mac, struct ether_addr *mac_out); -int get_nexthop_netlink(const char *mesh_iface, const struct ether_addr *mac, +int get_nexthop_netlink(struct state *state, const struct ether_addr *mac, uint8_t *nexthop, char *ifname); -int get_primarymac_netlink(const char *mesh_iface, uint8_t *primarymac); -int get_algoname_netlink(const char *mesh_iface, char *algoname, - size_t algoname_len); +int get_primarymac_netlink(struct state *state, uint8_t *primarymac); +int get_algoname_netlink(struct state *state, unsigned int mesh_ifindex, + char *algoname, size_t algoname_len);
extern struct nla_policy batadv_netlink_policy[];
diff --git a/ping.c b/ping.c index a9f0913..7565dcd 100644 --- a/ping.c +++ b/ping.c @@ -136,7 +136,7 @@ static int ping(struct state *state, int argc, char **argv) }
if (!disable_translate_mac) - dst_mac = translate_mac(state->mesh_iface, dst_mac); + dst_mac = translate_mac(state, dst_mac);
mac_string = ether_ntoa_long(dst_mac); signal(SIGINT, sig_handler); @@ -177,7 +177,7 @@ static int ping(struct state *state, int argc, char **argv)
icmp_packet_out.seqno = htons(++seq_counter);
- res = icmp_interface_write(state->mesh_iface, + res = icmp_interface_write(state, (struct batadv_icmp_header *)&icmp_packet_out, packet_len); if (res < 0) { @@ -323,5 +323,6 @@ static int ping(struct state *state, int argc, char **argv) return ret; }
-COMMAND(SUBCOMMAND_MIF, ping, "p", COMMAND_FLAG_MESH_IFACE, NULL, +COMMAND(SUBCOMMAND_MIF, ping, "p", + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, NULL, "<destination> \tping another batman adv host via layer 2"); diff --git a/routing_algo.c b/routing_algo.c index 01376bc..8fb4fab 100644 --- a/routing_algo.c +++ b/routing_algo.c @@ -168,6 +168,7 @@ static struct nla_policy link_policy[IFLA_MAX + 1] = {
struct print_ra_interfaces_rtnl_arg { uint8_t header_shown:1; + struct state *state; };
static int print_ra_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) @@ -190,7 +191,8 @@ static int print_ra_interfaces_rtnl_parse(struct nl_msg *msg, void *arg)
mesh_iface = nla_get_string(attrs[IFLA_IFNAME]);
- ret = get_algoname_netlink(mesh_iface, algoname, sizeof(algoname)); + ret = get_algoname_netlink(print_arg->state, ifm->ifi_index, algoname, + sizeof(algoname)); if (ret < 0) goto err;
@@ -205,9 +207,11 @@ static int print_ra_interfaces_rtnl_parse(struct nl_msg *msg, void *arg) return NL_OK; }
-static int print_ra_interfaces(void) +static int print_ra_interfaces(struct state *state) { - struct print_ra_interfaces_rtnl_arg print_arg = {}; + struct print_ra_interfaces_rtnl_arg print_arg = { + .state = state, + };
struct ifinfomsg rt_hdr = { .ifi_family = IFLA_UNSPEC, @@ -282,10 +286,11 @@ static int print_ra_interfaces(void) return err; }
-static int routing_algo(struct state *state __maybe_unused, int argc, char **argv) +static int routing_algo(struct state *state, int argc, char **argv) { int optchar; int res = EXIT_FAILURE; + int ret;
while ((optchar = getopt(argc, argv, "h")) != -1) { switch (optchar) { @@ -303,7 +308,15 @@ static int routing_algo(struct state *state __maybe_unused, int argc, char **arg if (argc == 2) return write_default_ra(SYS_SELECTED_RA_PATH, argv[1]);
- print_ra_interfaces(); + /* duplicated code here from the main() because interface doesn't always + * need COMMAND_FLAG_MESH_IFACE and COMMAND_FLAG_NETLINK + */ + ret = netlink_create(state); + if (ret < 0) + return EXIT_FAILURE; + + print_ra_interfaces(state); + netlink_destroy(state);
res = read_file(SYS_SELECTED_RA_PATH, USE_READ_BUFF); if (res != EXIT_SUCCESS) diff --git a/traceroute.c b/traceroute.c index 517962f..40e1e8f 100644 --- a/traceroute.c +++ b/traceroute.c @@ -97,7 +97,7 @@ static int traceroute(struct state *state, int argc, char **argv) }
if (!disable_translate_mac) - dst_mac = translate_mac(state->mesh_iface, dst_mac); + dst_mac = translate_mac(state, dst_mac);
mac_string = ether_ntoa_long(dst_mac);
@@ -124,7 +124,7 @@ static int traceroute(struct state *state, int argc, char **argv) icmp_packet_out.seqno = htons(++seq_counter); time_delta[i] = 0.0;
- res = icmp_interface_write(state->mesh_iface, + res = icmp_interface_write(state, (struct batadv_icmp_header *)&icmp_packet_out, sizeof(icmp_packet_out)); if (res < 0) { @@ -209,5 +209,6 @@ static int traceroute(struct state *state, int argc, char **argv) return ret; }
-COMMAND(SUBCOMMAND_MIF, traceroute, "tr", COMMAND_FLAG_MESH_IFACE, NULL, +COMMAND(SUBCOMMAND_MIF, traceroute, "tr", + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, NULL, "<destination> \ttraceroute another batman adv host via layer 2"); diff --git a/translate.c b/translate.c index 6eef476..92451c9 100644 --- a/translate.c +++ b/translate.c @@ -50,7 +50,7 @@ static int translate(struct state *state, int argc, char **argv) } }
- dst_mac = translate_mac(state->mesh_iface, dst_mac); + dst_mac = translate_mac(state, dst_mac); if (dst_mac) { mac_string = ether_ntoa_long(dst_mac); printf("%s\n", mac_string); @@ -64,5 +64,6 @@ static int translate(struct state *state, int argc, char **argv) return ret; }
-COMMAND(SUBCOMMAND_MIF, translate, "t", COMMAND_FLAG_MESH_IFACE, NULL, +COMMAND(SUBCOMMAND_MIF, translate, "t", + COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK, NULL, "<destination> \ttranslate a destination to the originator responsible for it");
The interface subcommand doesn't need to allocate a new netlink socket to get the list of interfaces. There is already a netlink socket available which was used to query the routing algorithm of each interface. Just use this batadv genl socket to also dump the list of all available routing algorithms.
Signed-off-by: Sven Eckelmann sven@narfation.org --- routing_algo.c | 53 ++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 36 deletions(-)
diff --git a/routing_algo.c b/routing_algo.c index 8fb4fab..0adf32f 100644 --- a/routing_algo.c +++ b/routing_algo.c @@ -79,58 +79,35 @@ static int routing_algos_callback(struct nl_msg *msg, void *arg __maybe_unused) return NL_OK; }
-static int print_routing_algos(void) +static int print_routing_algos(struct state *state) { - struct nl_sock *sock; struct nl_msg *msg; struct nl_cb *cb; - int family; struct print_opts opts = { .callback = routing_algos_callback, };
- sock = nl_socket_alloc(); - if (!sock) - return -ENOMEM; - - genl_connect(sock); - - family = genl_ctrl_resolve(sock, BATADV_NL_NAME); - if (family < 0) { - last_err = -EOPNOTSUPP; - goto err_free_sock; - } - msg = nlmsg_alloc(); - if (!msg) { - last_err = -ENOMEM; - goto err_free_sock; - } - - genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_DUMP, - BATADV_CMD_GET_ROUTING_ALGOS, 1); - - nl_send_auto_complete(sock, msg); + if (!msg) + return -ENOMEM;
+ genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, state->batadv_family, 0, + NLM_F_DUMP, BATADV_CMD_GET_ROUTING_ALGOS, 1); + nl_send_auto_complete(state->sock, msg); nlmsg_free(msg);
opts.remaining_header = strdup("Available routing algorithms:\n");
cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!cb) { - last_err = -ENOMEM; - goto err_free_sock; - } + if (!cb) + return -ENOMEM;
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, netlink_print_common_cb, &opts); nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, netlink_stop_callback, NULL); nl_cb_err(cb, NL_CB_CUSTOM, netlink_print_error, NULL);
- nl_recvmsgs(sock, cb); - -err_free_sock: - nl_socket_free(sock); + nl_recvmsgs(state->sock, cb);
if (!last_err) netlink_print_remaining_header(&opts); @@ -316,19 +293,23 @@ static int routing_algo(struct state *state, int argc, char **argv) return EXIT_FAILURE;
print_ra_interfaces(state); - netlink_destroy(state);
res = read_file(SYS_SELECTED_RA_PATH, USE_READ_BUFF); if (res != EXIT_SUCCESS) - return EXIT_FAILURE; + goto err_free_netlink;
printf("Selected routing algorithm (used when next batX interface is created):\n"); printf(" => %s\n", line_ptr); free(line_ptr); line_ptr = NULL;
- print_routing_algos(); - return EXIT_SUCCESS; + print_routing_algos(state); + res = EXIT_SUCCESS; + +err_free_netlink: + netlink_destroy(state); + + return res; }
COMMAND(SUBCOMMAND, routing_algo, "ra", 0, NULL,
b.a.t.m.a.n@lists.open-mesh.org