Dump the list of DAT cache entries via the netlink socket.
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue --- batman_adv.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/batman_adv.h b/batman_adv.h index 56ae289..85c9fe8 100644 --- a/batman_adv.h +++ b/batman_adv.h @@ -272,6 +272,21 @@ enum batadv_nl_attrs { */ BATADV_ATTR_BLA_CRC,
+ /** + * @BATADV_ATTR_DC_ADDRESS: Client IPv4 address + */ + BATADV_ATTR_DC_ADDRESS, + + /** + * @BATADV_ATTR_DC_HWADDRESS: Client MAC address + */ + BATADV_ATTR_DC_HWADDRESS, + + /** + * @BATADV_ATTR_DC_VID: VLAN ID + */ + BATADV_ATTR_DC_VID, + /* add attributes above here, update the policy in netlink.c */
/** @@ -361,6 +376,11 @@ enum batadv_nl_commands { */ BATADV_CMD_GET_BLA_BACKBONE,
+ /** + * @BATADV_CMD_GET_DAT_CACHE: Query list of DAT cache entries + */ + BATADV_CMD_GET_DAT_CACHE, + /* add new commands above here */
/**
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue --- debug.c | 1 + netlink.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netlink.h | 2 ++ 3 files changed, 106 insertions(+)
diff --git a/debug.c b/debug.c index a7c5adf..5f9a87b 100644 --- a/debug.c +++ b/debug.c @@ -87,6 +87,7 @@ const struct debug_table_data batctl_debug_tables[BATCTL_TABLE_NUM] = { .opt_short = "dc", .debugfs_name = "dat_cache", .header_lines = 2, + .netlink_fn = netlink_print_dat_cache, }, { .opt_long = "nc_nodes", diff --git a/netlink.c b/netlink.c index 126066b..35f74c9 100644 --- a/netlink.c +++ b/netlink.c @@ -118,6 +118,11 @@ struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { .minlen = ETH_ALEN, .maxlen = ETH_ALEN }, [BATADV_ATTR_BLA_CRC] = { .type = NLA_U16 }, + [BATADV_ATTR_DC_ADDRESS] = { .type = NLA_U32 }, + [BATADV_ATTR_DC_HWADDRESS] = { .type = NLA_UNSPEC, + .minlen = ETH_ALEN, + .maxlen = ETH_ALEN }, + [BATADV_ATTR_DC_VID] = { .type = NLA_U16 }, };
static int last_err; @@ -1104,6 +1109,82 @@ static int bla_backbone_callback(struct nl_msg *msg, void *arg) return NL_OK; }
+static const int dat_cache_mandatory[] = { + BATADV_ATTR_DC_ADDRESS, + BATADV_ATTR_DC_HWADDRESS, + BATADV_ATTR_DC_VID, + BATADV_ATTR_LAST_SEEN_MSECS, +}; + +static int dat_cache_callback(struct nl_msg *msg, void *arg) +{ + int last_seen_msecs, last_seen_secs, last_seen_mins; + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct print_opts *opts = arg; + struct bat_host *bat_host; + struct genlmsghdr *ghdr; + struct in_addr in_addr; + uint8_t *hwaddr; + uint32_t u_addr; + int16_t vid; + char *addr; + + if (!genlmsg_valid_hdr(nlh, 0)) { + fputs("Received invalid data from kernel.\n", stderr); + exit(1); + } + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_DAT_CACHE) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + fputs("Received invalid data from kernel.\n", stderr); + exit(1); + } + + if (missing_mandatory_attrs(attrs, dat_cache_mandatory, + ARRAY_SIZE(dat_cache_mandatory))) { + fputs("Missing attributes from kernel\n", stderr); + exit(1); + } + + u_addr = nla_get_u32(attrs[BATADV_ATTR_DC_ADDRESS]); + in_addr.s_addr = htonl(u_addr); + addr = inet_ntoa(in_addr); + hwaddr = nla_data(attrs[BATADV_ATTR_DC_HWADDRESS]); + vid = nla_get_u16(attrs[BATADV_ATTR_DC_VID]); + + last_seen_msecs = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); + last_seen_mins = last_seen_msecs / 60000; + last_seen_msecs = last_seen_msecs % 60000; + last_seen_secs = last_seen_msecs / 1000; + + if (opts->read_opt & MULTICAST_ONLY && !(addr[0] & 0x01)) + return NL_OK; + + if (opts->read_opt & UNICAST_ONLY && (addr[0] & 0x01)) + return NL_OK; + + printf(" * %15s ", addr); + + bat_host = bat_hosts_find_by_mac((char *)hwaddr); + if (!(opts->read_opt & USE_BAT_HOSTS) || !bat_host) + printf("%02x:%02x:%02x:%02x:%02x:%02x ", + hwaddr[0], hwaddr[1], hwaddr[2], + hwaddr[3], hwaddr[4], hwaddr[5]); + else + printf("%17s ", bat_host->name); + + printf("%4i %6i:%02i\n", + BATADV_PRINT_VID(vid), last_seen_mins, last_seen_secs); + + return NL_OK; +} + static int netlink_print_common(char *mesh_iface, char *orig_iface, int read_opt, float orig_timeout, float watch_interval, const char *header, @@ -1336,6 +1417,28 @@ int netlink_print_bla_backbone(char *mesh_iface, char *orig_iface, int read_opts bla_backbone_callback); }
+int netlink_print_dat_cache(char *mesh_iface, char *orig_iface, int read_opts, + float orig_timeout, float watch_interval) +{ + char *header; + int ret; + + ret = asprintf(&header, "Distributed ARP Table (%s):\n%s\n", + mesh_iface, + " IPv4 MAC VID last-seen"); + + if (ret < 0) + return ret; + + ret = netlink_print_common(mesh_iface, orig_iface, read_opts, + orig_timeout, watch_interval, header, + BATADV_CMD_GET_DAT_CACHE, + dat_cache_callback); + + free(header); + return ret; +} + static int nlquery_error_cb(struct sockaddr_nl *nla __maybe_unused, struct nlmsgerr *nlerr, void *arg) { diff --git a/netlink.h b/netlink.h index a75e5cf..57870c2 100644 --- a/netlink.h +++ b/netlink.h @@ -45,6 +45,8 @@ int netlink_print_bla_claim(char *mesh_iface, char *orig_iface, int read_opt, float orig_timeout, float watch_interval); int netlink_print_bla_backbone(char *mesh_iface, char *orig_iface, int read_opt, float orig_timeout, float watch_interval); +int netlink_print_dat_cache(char *mesh_iface, char *orig_iface, int read_opt, + float orig_timeout, float watch_interval);
int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac, struct ether_addr *mac_out);
Dump the list of multicast flags entries via the netlink socket.
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue --- batman_adv.h | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+)
diff --git a/batman_adv.h b/batman_adv.h index 85c9fe8..d17ea7a 100644 --- a/batman_adv.h +++ b/batman_adv.h @@ -92,6 +92,53 @@ enum batadv_tt_client_flags { };
/** + * enum batadv_mcast_flags_priv - Private, own multicast flags + * + * These are internal, multicast related flags. Currently they describe certain + * multicast related attributes of the segment this originator bridges into the + * mesh. + * + * Those attributes are used to determine the public multicast flags this + * originator is going to announce via TT. + * + * For netlink, if BATADV_MCAST_FLAGS_BRIDGED is unset then all querier + * related flags are undefined. + */ +enum batadv_mcast_flags_priv { + /** + * @BATADV_MCAST_FLAGS_BRIDGED: There is a bridge on top of the mesh + * interface. + */ + BATADV_MCAST_FLAGS_BRIDGED = (1 << 0), + + /** + * @BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS: Whether an IGMP querier + * exists in the mesh + */ + BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS = (1 << 1), + + /** + * @BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS: Whether an MLD querier + * exists in the mesh + */ + BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS = (1 << 2), + + /** + * @BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING: If an IGMP querier + * exists, whether it is potentially shadowing multicast listeners + * (i.e. querier is behind our own bridge segment) + */ + BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING = (1 << 3), + + /** + * @BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING: If an MLD querier + * exists, whether it is potentially shadowing multicast listeners + * (i.e. querier is behind our own bridge segment) + */ + BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING = (1 << 4), +}; + +/** * enum batadv_nl_attrs - batman-adv netlink attributes */ enum batadv_nl_attrs { @@ -287,6 +334,16 @@ enum batadv_nl_attrs { */ BATADV_ATTR_DC_VID,
+ /** + * @BATADV_ATTR_MCAST_FLAGS: Per originator multicast flags + */ + BATADV_ATTR_MCAST_FLAGS, + + /** + * @BATADV_ATTR_MCAST_FLAGS_PRIV: Private, own multicast flags + */ + BATADV_ATTR_MCAST_FLAGS_PRIV, + /* add attributes above here, update the policy in netlink.c */
/** @@ -381,6 +438,11 @@ enum batadv_nl_commands { */ BATADV_CMD_GET_DAT_CACHE,
+ /** + * @BATADV_CMD_GET_MCAST_FLAGS: Query list of multicast flags + */ + BATADV_CMD_GET_MCAST_FLAGS, + /* add new commands above here */
/**
Signed-off-by: Linus Lüssing linus.luessing@c0d3.blue --- debug.c | 1 + netlink.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netlink.h | 2 + 3 files changed, 146 insertions(+)
diff --git a/debug.c b/debug.c index 5f9a87b..63fb633 100644 --- a/debug.c +++ b/debug.c @@ -100,6 +100,7 @@ const struct debug_table_data batctl_debug_tables[BATCTL_TABLE_NUM] = { .opt_short = "mf", .debugfs_name = "mcast_flags", .header_lines = 6, + .netlink_fn = netlink_print_mcast_flags, }, };
diff --git a/netlink.c b/netlink.c index 35f74c9..996067d 100644 --- a/netlink.c +++ b/netlink.c @@ -123,10 +123,14 @@ struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = { .minlen = ETH_ALEN, .maxlen = ETH_ALEN }, [BATADV_ATTR_DC_VID] = { .type = NLA_U16 }, + [BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U8 }, + [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U8 }, };
static int last_err; static char algo_name_buf[256] = ""; +static int mcast_flags = -EINVAL; +static int mcast_flags_priv = -EINVAL;
static int missing_mandatory_attrs(struct nlattr *attrs[], const int mandatory[], int num) @@ -240,6 +244,16 @@ static int info_callback(struct nl_msg *msg, void *arg) if (attrs[BATADV_ATTR_BLA_CRC]) bla_group_id = nla_get_u16(attrs[BATADV_ATTR_BLA_CRC]);
+ if (attrs[BATADV_ATTR_MCAST_FLAGS]) + mcast_flags = nla_get_u8(attrs[BATADV_ATTR_MCAST_FLAGS]); + else + mcast_flags = -EINVAL; + + if (attrs[BATADV_ATTR_MCAST_FLAGS_PRIV]) + mcast_flags_priv = nla_get_u8(attrs[BATADV_ATTR_MCAST_FLAGS_PRIV]); + else + mcast_flags = -EINVAL; + switch (opts->nl_cmd) { case BATADV_CMD_GET_TRANSTABLE_LOCAL: ret = asprintf(&extra_info, ", TTVN: %u", ttvn); @@ -1185,6 +1199,72 @@ static int dat_cache_callback(struct nl_msg *msg, void *arg) return NL_OK; }
+static const int mcast_flags_mandatory[] = { + BATADV_ATTR_ORIG_ADDRESS, +}; + +static int mcast_flags_callback(struct nl_msg *msg, void *arg) +{ + struct nlattr *attrs[BATADV_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct print_opts *opts = arg; + struct bat_host *bat_host; + struct genlmsghdr *ghdr; + uint8_t *addr; + uint8_t flags; + + if (!genlmsg_valid_hdr(nlh, 0)) { + fputs("Received invalid data from kernel.\n", stderr); + exit(1); + } + + ghdr = nlmsg_data(nlh); + + if (ghdr->cmd != BATADV_CMD_GET_MCAST_FLAGS) + return NL_OK; + + if (nla_parse(attrs, BATADV_ATTR_MAX, genlmsg_attrdata(ghdr, 0), + genlmsg_len(ghdr), batadv_netlink_policy)) { + fputs("Received invalid data from kernel.\n", stderr); + exit(1); + } + + if (missing_mandatory_attrs(attrs, mcast_flags_mandatory, + ARRAY_SIZE(mcast_flags_mandatory))) { + fputs("Missing attributes from kernel\n", stderr); + exit(1); + } + + addr = nla_data(attrs[BATADV_ATTR_ORIG_ADDRESS]); + + if (opts->read_opt & MULTICAST_ONLY && !(addr[0] & 0x01)) + return NL_OK; + + if (opts->read_opt & UNICAST_ONLY && (addr[0] & 0x01)) + return NL_OK; + + bat_host = bat_hosts_find_by_mac((char *)addr); + if (!(opts->read_opt & USE_BAT_HOSTS) || !bat_host) + printf("%02x:%02x:%02x:%02x:%02x:%02x ", + addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); + else + printf("%17s ", bat_host->name); + + if (attrs[BATADV_ATTR_MCAST_FLAGS]) { + flags = nla_get_u8(attrs[BATADV_ATTR_MCAST_FLAGS]); + + printf("[%c%c%c]\n", + flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES ? 'U' : '.', + flags & BATADV_MCAST_WANT_ALL_IPV4 ? '4' : '.', + flags & BATADV_MCAST_WANT_ALL_IPV6 ? '6' : '.'); + } else { + printf("-\n"); + } + + return NL_OK; +} + static int netlink_print_common(char *mesh_iface, char *orig_iface, int read_opt, float orig_timeout, float watch_interval, const char *header, @@ -1439,6 +1519,69 @@ int netlink_print_dat_cache(char *mesh_iface, char *orig_iface, int read_opts, return ret; }
+int netlink_print_mcast_flags(char *mesh_iface, char *orig_iface, int read_opts, + float orig_timeout, float watch_interval) +{ + char querier4, querier6, shadowing4, shadowing6; + char *info_header; + char *header; + bool bridged; + int ifindex; + int ret; + + ifindex = if_nametoindex(mesh_iface); + if (!ifindex) { + fprintf(stderr, "Interface %s is unknown\n", mesh_iface); + return -ENODEV; + } + + /* only parse own multicast flags */ + info_header = netlink_get_info(ifindex, BATADV_CMD_GET_MCAST_FLAGS, NULL); + free(info_header); + + if (mcast_flags < 0 || mcast_flags_priv < 0) + return -EINVAL; + + bridged = mcast_flags_priv & BATADV_MCAST_FLAGS_BRIDGED; + + if (bridged) { + querier4 = (mcast_flags_priv & BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS) ? '.' : '4'; + querier6 = (mcast_flags_priv & BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS) ? '.' : '6'; + shadowing4 = (mcast_flags_priv & BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING) ? '4' : '.'; + shadowing6 = (mcast_flags_priv & BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING) ? '6' : '.'; + } else { + querier4 = '?'; + querier6 = '?'; + shadowing4 = '?'; + shadowing6 = '?'; + } + + ret = asprintf(&header, + "Multicast flags (own flags: [%c%c%c])\n" + "* Bridged [U]\t\t\t\t%c\n" + "* No IGMP/MLD Querier [4/6]:\t\t%c/%c\n" + "* Shadowing IGMP/MLD Querier [4/6]:\t%c/%c\n" + "-------------------------------------------\n" + " %-10s %s\n", + (mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.', + (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.', + (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.', + bridged ? 'U' : '.', + querier4, querier6, shadowing4, shadowing6, + "Originator", "Flags"); + + if (ret < 0) + return ret; + + ret = netlink_print_common(mesh_iface, orig_iface, read_opts, + orig_timeout, watch_interval, header, + BATADV_CMD_GET_MCAST_FLAGS, + mcast_flags_callback); + + free(header); + return ret; +} + static int nlquery_error_cb(struct sockaddr_nl *nla __maybe_unused, struct nlmsgerr *nlerr, void *arg) { diff --git a/netlink.h b/netlink.h index 57870c2..089e25e 100644 --- a/netlink.h +++ b/netlink.h @@ -47,6 +47,8 @@ int netlink_print_bla_backbone(char *mesh_iface, char *orig_iface, int read_opt, float orig_timeout, float watch_interval); int netlink_print_dat_cache(char *mesh_iface, char *orig_iface, int read_opt, float orig_timeout, float watch_interval); +int netlink_print_mcast_flags(char *mesh_iface, char *orig_iface, int read_opt, + float orig_timeout, float watch_interval);
int translate_mac_netlink(const char *mesh_iface, const struct ether_addr *mac, struct ether_addr *mac_out);
On Dienstag, 27. Februar 2018 09:10:59 CET Linus Lüssing wrote:
/* only parse own multicast flags */
info_header = netlink_get_info(ifindex, BATADV_CMD_GET_MCAST_FLAGS, NULL);
free(info_header);
if (mcast_flags < 0 || mcast_flags_priv < 0)
return -EINVAL;
Let us assume for now that the kernel doesn't yet support the netlink mcast_flags and the rest of the mcast netlink code. It will now try to get the mcast_flags from the kernel and fail. Thsi function is now returning -EINVAL and handle_debug_table will now compare the return code to -EOPNOTSUPP and notice that a different error happened and stops the processing. Would be nice when it would not really stop and instead try to get the data from debugfs (via the old code which is still in batctl).
Kind regards, Sven
b.a.t.m.a.n@lists.open-mesh.org