+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Get mdb table with netlink
*/
#include <linux/if_ether.h>
#include <string.h>
#include <arpa/inet.h>
-#include <json_writer.h>
#include "libnetlink.h"
#include "br_common.h"
#include "rt_names.h"
#include "utils.h"
+#include "json_print.h"
#ifndef MDBA_RTA
#define MDBA_RTA(r) \
#endif
static unsigned int filter_index, filter_vlan;
-json_writer_t *jw_global;
-static bool print_mdb_entries = true;
-static bool print_mdb_router = true;
static void usage(void)
{
return type == MDB_RTR_TYPE_TEMP_QUERY || type == MDB_RTR_TYPE_TEMP;
}
+static const char *format_timer(__u32 ticks)
+{
+ struct timeval tv;
+ static char tbuf[32];
+
+ __jiffies_to_tv(&tv, ticks);
+ snprintf(tbuf, sizeof(tbuf), "%4lu.%.2lu",
+ (unsigned long)tv.tv_sec,
+ (unsigned long)tv.tv_usec / 10000);
+
+ return tbuf;
+}
+
static void __print_router_port_stats(FILE *f, struct rtattr *pattr)
{
struct rtattr *tb[MDBA_ROUTER_PATTR_MAX + 1];
- struct timeval tv;
- __u8 type;
parse_rtattr(tb, MDBA_ROUTER_PATTR_MAX, MDB_RTR_RTA(RTA_DATA(pattr)),
RTA_PAYLOAD(pattr) - RTA_ALIGN(sizeof(uint32_t)));
+
if (tb[MDBA_ROUTER_PATTR_TIMER]) {
- __jiffies_to_tv(&tv,
- rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]));
- if (jw_global) {
- char formatted_time[9];
-
- snprintf(formatted_time, sizeof(formatted_time),
- "%4i.%.2i", (int)tv.tv_sec,
- (int)tv.tv_usec/10000);
- jsonw_string_field(jw_global, "timer", formatted_time);
- } else {
- fprintf(f, " %4i.%.2i",
- (int)tv.tv_sec, (int)tv.tv_usec/10000);
- }
+ __u32 timer = rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]);
+
+ print_string(PRINT_ANY, "timer", " %s",
+ format_timer(timer));
}
+
if (tb[MDBA_ROUTER_PATTR_TYPE]) {
- type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
- if (jw_global)
- jsonw_string_field(jw_global, "type",
- is_temp_mcast_rtr(type) ? "temp" : "permanent");
- else
- fprintf(f, " %s",
- is_temp_mcast_rtr(type) ? "temp" : "permanent");
+ __u8 type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
+
+ print_string(PRINT_ANY, "type", " %s",
+ is_temp_mcast_rtr(type) ? "temp" : "permanent");
}
}
-static void br_print_router_ports(FILE *f, struct rtattr *attr, __u32 brifidx)
+static void br_print_router_ports(FILE *f, struct rtattr *attr,
+ const char *brifname)
{
- uint32_t *port_ifindex;
+ int rem = RTA_PAYLOAD(attr);
struct rtattr *i;
- int rem;
- rem = RTA_PAYLOAD(attr);
- if (jw_global) {
- jsonw_name(jw_global, ll_index_to_name(brifidx));
- jsonw_start_array(jw_global);
- for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
- port_ifindex = RTA_DATA(i);
- jsonw_start_object(jw_global);
- jsonw_string_field(jw_global,
- "port",
- ll_index_to_name(*port_ifindex));
+ if (is_json_context())
+ open_json_array(PRINT_JSON, brifname);
+ else if (!show_stats)
+ fprintf(f, "router ports on %s: ", brifname);
+
+ for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+ uint32_t *port_ifindex = RTA_DATA(i);
+ const char *port_ifname = ll_index_to_name(*port_ifindex);
+
+ if (is_json_context()) {
+ open_json_object(NULL);
+ print_string(PRINT_JSON, "port", NULL, port_ifname);
+
if (show_stats)
__print_router_port_stats(f, i);
- jsonw_end_object(jw_global);
- }
- jsonw_end_array(jw_global);
- } else {
- if (!show_stats)
- fprintf(f, "router ports on %s: ",
- ll_index_to_name(brifidx));
- for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
- port_ifindex = RTA_DATA(i);
- if (show_stats) {
- fprintf(f, "router ports on %s: %s",
- ll_index_to_name(brifidx),
- ll_index_to_name(*port_ifindex));
- __print_router_port_stats(f, i);
- fprintf(f, "\n");
- } else{
- fprintf(f, "%s ",
- ll_index_to_name(*port_ifindex));
- }
- }
- if (!show_stats)
+ close_json_object();
+ } else if (show_stats) {
+ fprintf(f, "router ports on %s: %s",
+ brifname, port_ifname);
+
+ __print_router_port_stats(f, i);
fprintf(f, "\n");
+ } else {
+ fprintf(f, "%s ", port_ifname);
+ }
}
-}
-static void start_json_mdb_flags_array(bool *mdb_flags)
-{
- if (*mdb_flags)
- return;
- jsonw_name(jw_global, "flags");
- jsonw_start_array(jw_global);
- *mdb_flags = true;
+ if (!show_stats)
+ print_nl();
+
+ close_json_array(PRINT_JSON, NULL);
}
-static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
+static void print_mdb_entry(FILE *f, int ifindex, const struct br_mdb_entry *e,
struct nlmsghdr *n, struct rtattr **tb)
{
SPRINT_BUF(abuf);
+ const char *dev;
const void *src;
int af;
- bool mdb_flags = false;
if (filter_vlan && e->vid != filter_vlan)
return;
+
af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6;
src = af == AF_INET ? (const void *)&e->addr.u.ip4 :
(const void *)&e->addr.u.ip6;
- if (jw_global)
- jsonw_start_object(jw_global);
- if (n->nlmsg_type == RTM_DELMDB) {
- if (jw_global)
- jsonw_string_field(jw_global, "opCode", "deleted");
- else
- fprintf(f, "Deleted ");
- }
- if (jw_global) {
- jsonw_string_field(jw_global, "dev", ll_index_to_name(ifindex));
- jsonw_string_field(jw_global,
- "port",
- ll_index_to_name(e->ifindex));
- jsonw_string_field(jw_global, "grp", inet_ntop(af, src,
- abuf, sizeof(abuf)));
- jsonw_string_field(jw_global, "state",
- (e->state & MDB_PERMANENT) ? "permanent" : "temp");
- if (e->flags & MDB_FLAGS_OFFLOAD) {
- start_json_mdb_flags_array(&mdb_flags);
- jsonw_string(jw_global, "offload");
- }
- if (mdb_flags)
- jsonw_end_array(jw_global);
- } else{
- fprintf(f, "dev %s port %s grp %s %s %s",
- ll_index_to_name(ifindex),
- ll_index_to_name(e->ifindex),
- inet_ntop(af, src, abuf, sizeof(abuf)),
- (e->state & MDB_PERMANENT) ? "permanent" : "temp",
- (e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : "");
- }
- if (e->vid) {
- if (jw_global)
- jsonw_uint_field(jw_global, "vid", e->vid);
- else
- fprintf(f, " vid %hu", e->vid);
- }
- if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
- struct timeval tv;
+ dev = ll_index_to_name(ifindex);
- __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]));
- if (jw_global) {
- char formatted_time[9];
+ open_json_object(NULL);
- snprintf(formatted_time, sizeof(formatted_time),
- "%4i.%.2i", (int)tv.tv_sec,
- (int)tv.tv_usec/10000);
- jsonw_string_field(jw_global, "timer", formatted_time);
- } else {
- fprintf(f, "%4i.%.2i", (int)tv.tv_sec,
- (int)tv.tv_usec/10000);
- }
+ if (n->nlmsg_type == RTM_DELMDB)
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
+ print_int(PRINT_ANY, "index", "%u: ", ifindex);
+ print_color_string(PRINT_ANY, COLOR_IFNAME, "dev", "%s ", dev);
+ print_string(PRINT_ANY, "port", " %s ",
+ ll_index_to_name(e->ifindex));
+
+ print_color_string(PRINT_ANY, ifa_family_color(af),
+ "grp", " %s ",
+ inet_ntop(af, src, abuf, sizeof(abuf)));
+
+ print_string(PRINT_ANY, "state", " %s ",
+ (e->state & MDB_PERMANENT) ? "permanent" : "temp");
+
+ open_json_array(PRINT_JSON, "flags");
+ if (e->flags & MDB_FLAGS_OFFLOAD)
+ print_string(PRINT_ANY, NULL, "%s ", "offload");
+ close_json_array(PRINT_JSON, NULL);
+
+ if (e->vid)
+ print_uint(PRINT_ANY, "vid", " vid %u", e->vid);
+
+ if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
+ __u32 timer = rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]);
+
+ print_string(PRINT_ANY, "timer", " %s",
+ format_timer(timer));
}
- if (jw_global)
- jsonw_end_object(jw_global);
- else
- fprintf(f, "\n");
+
+ print_nl();
+ close_json_object();
}
static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
}
}
+static void print_mdb_entries(FILE *fp, struct nlmsghdr *n,
+ int ifindex, struct rtattr *mdb)
+{
+ int rem = RTA_PAYLOAD(mdb);
+ struct rtattr *i;
+
+ open_json_array(PRINT_JSON, "mdb");
+ for (i = RTA_DATA(mdb); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+ br_print_mdb_entry(fp, ifindex, i, n);
+ close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_router_entries(FILE *fp, struct nlmsghdr *n,
+ int ifindex, struct rtattr *router)
+{
+ const char *brifname = ll_index_to_name(ifindex);
+
+ open_json_array(PRINT_JSON, "router");
+ if (n->nlmsg_type == RTM_GETMDB) {
+ if (show_details)
+ br_print_router_ports(fp, router, brifname);
+ } else {
+ struct rtattr *i = RTA_DATA(router);
+ uint32_t *port_ifindex = RTA_DATA(i);
+ const char *port_name = ll_index_to_name(*port_ifindex);
+
+ if (is_json_context()) {
+ open_json_array(PRINT_JSON, brifname);
+ open_json_object(NULL);
+
+ print_string(PRINT_JSON, "port", NULL,
+ port_name);
+ close_json_object();
+ close_json_array(PRINT_JSON, NULL);
+ } else {
+ fprintf(fp, "router port dev %s master %s\n",
+ port_name, brifname);
+ }
+ }
+ close_json_array(PRINT_JSON, NULL);
+}
+
int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
FILE *fp = arg;
struct br_port_msg *r = NLMSG_DATA(n);
int len = n->nlmsg_len;
- struct rtattr *tb[MDBA_MAX+1], *i;
+ struct rtattr *tb[MDBA_MAX+1];
- if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) {
- fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
+ if (n->nlmsg_type != RTM_GETMDB &&
+ n->nlmsg_type != RTM_NEWMDB &&
+ n->nlmsg_type != RTM_DELMDB) {
+ fprintf(stderr,
+ "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
return 0;
parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
- if (tb[MDBA_MDB] && print_mdb_entries) {
- int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
-
- for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
- br_print_mdb_entry(fp, r->ifindex, i, n);
- }
+ if (n->nlmsg_type == RTM_DELMDB)
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
- if (tb[MDBA_ROUTER] && print_mdb_router) {
- if (n->nlmsg_type == RTM_GETMDB) {
- if (show_details)
- br_print_router_ports(fp, tb[MDBA_ROUTER],
- r->ifindex);
- } else {
- uint32_t *port_ifindex;
-
- i = RTA_DATA(tb[MDBA_ROUTER]);
- port_ifindex = RTA_DATA(i);
- if (n->nlmsg_type == RTM_DELMDB) {
- if (jw_global)
- jsonw_string_field(jw_global,
- "opCode",
- "deleted");
- else
- fprintf(fp, "Deleted ");
- }
- if (jw_global) {
- jsonw_name(jw_global,
- ll_index_to_name(r->ifindex));
- jsonw_start_array(jw_global);
- jsonw_start_object(jw_global);
- jsonw_string_field(jw_global, "port",
- ll_index_to_name(*port_ifindex));
- jsonw_end_object(jw_global);
- jsonw_end_array(jw_global);
- } else {
- fprintf(fp, "router port dev %s master %s\n",
- ll_index_to_name(*port_ifindex),
- ll_index_to_name(r->ifindex));
- }
- }
- }
+ if (tb[MDBA_MDB])
+ print_mdb_entries(fp, n, r->ifindex, tb[MDBA_MDB]);
- if (!jw_global)
- fflush(fp);
+ if (tb[MDBA_ROUTER])
+ print_router_entries(fp, n, r->ifindex, tb[MDBA_ROUTER]);
return 0;
}
}
if (filter_dev) {
- filter_index = if_nametoindex(filter_dev);
- if (filter_index == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- filter_dev);
- return -1;
- }
+ filter_index = ll_name_to_index(filter_dev);
+ if (!filter_index)
+ return nodev(filter_dev);
}
+ new_json_obj(json);
+
/* get mdb entries*/
if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
perror("Cannot send dump request");
return -1;
}
- if (!json_output) {
- /* Normal output */
- if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
- fprintf(stderr, "Dump terminated\n");
- return -1;
- }
- return 0;
- }
- /* Json output */
- jw_global = jsonw_new(stdout);
- jsonw_pretty(jw_global, 1);
- jsonw_start_object(jw_global);
- jsonw_name(jw_global, "mdb");
- jsonw_start_array(jw_global);
-
- /* print mdb entries */
- print_mdb_entries = true;
- print_mdb_router = false;
if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
fprintf(stderr, "Dump terminated\n");
return -1;
}
- jsonw_end_array(jw_global);
- /* get router ports */
- if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
- perror("Cannot send dump request");
- return -1;
- }
- jsonw_name(jw_global, "router");
- jsonw_start_object(jw_global);
-
- /* print router ports */
- print_mdb_entries = false;
- print_mdb_router = true;
- if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
- fprintf(stderr, "Dump terminated\n");
- return -1;
- }
- jsonw_end_object(jw_global);
- jsonw_end_object(jw_global);
- jsonw_destroy(&jw_global);
+ delete_json_obj();
+ fflush(stdout);
return 0;
}
}
req.bpm.ifindex = ll_name_to_index(d);
- if (req.bpm.ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", d);
- return -1;
- }
+ if (!req.bpm.ifindex)
+ return nodev(d);
entry.ifindex = ll_name_to_index(p);
- if (entry.ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", p);
- return -1;
- }
+ if (!entry.ifindex)
+ return nodev(p);
if (!inet_pton(AF_INET, grp, &entry.addr.u.ip4)) {
if (!inet_pton(AF_INET6, grp, &entry.addr.u.ip6)) {
entry.vid = vid;
addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry));
- if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
+ if (rtnl_talk(&rth, &req.n, NULL) < 0)
return -1;
return 0;