" [ mcast_router MULTICAST_ROUTER ]\n"
" [ mcast_fast_leave {on | off} ]\n"
" [ mcast_flood {on | off} ]\n"
+ " [ group_fwd_mask MASK ]\n"
+ " [ neigh_suppress {on | off} ]\n"
+ " [ vlan_tunnel {on | off} ]\n"
+ " [ isolated {on | off} ]\n"
+ " [ backup_port DEVICE ] [ nobackup_port ]\n"
);
}
[BR_STATE_BLOCKING] = "blocking",
};
+static const char *fwd_mask_tbl[16] = {
+ [0] = "stp",
+ [2] = "lacp",
+ [14] = "lldp"
+};
+
static void print_portstate(FILE *f, __u8 state)
{
if (state <= BR_STATE_BLOCKING)
fprintf(f, "%s %s ", flag, val ? "on" : "off");
}
-static void _print_hex(FILE *f,
- const char *json_attr,
- const char *attr,
- __u16 val)
-{
- if (is_json_context()) {
- SPRINT_BUF(b1);
-
- snprintf(b1, sizeof(b1), "0x%x", val);
- print_string(PRINT_JSON, json_attr, NULL, b1);
- } else {
- fprintf(f, "%s 0x%x ", attr, val);
- }
-}
-
static void _print_timer(FILE *f, const char *attr, struct rtattr *timer)
{
struct timeval tv;
}
}
+static void _bitmask2str(__u16 bitmask, char *dst, size_t dst_size,
+ const char **tbl)
+{
+ int len, i;
+
+ for (i = 0, len = 0; bitmask; i++, bitmask >>= 1) {
+ if (bitmask & 0x1) {
+ if (tbl[i])
+ len += snprintf(dst + len, dst_size - len, "%s,",
+ tbl[i]);
+ else
+ len += snprintf(dst + len, dst_size - len, "0x%x,",
+ (1 << i));
+ }
+ }
+
+ if (!len)
+ snprintf(dst, dst_size, "0x0");
+ else
+ dst[len - 1] = 0;
+}
+
static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
struct rtattr *tb[])
{
rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]));
if (tb[IFLA_BRPORT_ID])
- _print_hex(f, "id", "port_id",
- rta_getattr_u16(tb[IFLA_BRPORT_ID]));
+ print_0xhex(PRINT_ANY, "id", "port_id 0x%x ",
+ rta_getattr_u16(tb[IFLA_BRPORT_ID]));
if (tb[IFLA_BRPORT_NO])
- _print_hex(f, "no", "port_no",
+ print_0xhex(PRINT_ANY, "no", "port_no 0x%x ",
rta_getattr_u16(tb[IFLA_BRPORT_NO]));
if (tb[IFLA_BRPORT_DESIGNATED_PORT])
if (tb[IFLA_BRPORT_NEIGH_SUPPRESS])
_print_onoff(f, "neigh_suppress", "neigh_suppress",
rta_getattr_u8(tb[IFLA_BRPORT_NEIGH_SUPPRESS]));
+
+ if (tb[IFLA_BRPORT_GROUP_FWD_MASK]) {
+ char convbuf[256];
+ __u16 fwd_mask;
+
+ fwd_mask = rta_getattr_u16(tb[IFLA_BRPORT_GROUP_FWD_MASK]);
+ print_0xhex(PRINT_ANY, "group_fwd_mask",
+ "group_fwd_mask 0x%x ", fwd_mask);
+ _bitmask2str(fwd_mask, convbuf, sizeof(convbuf), fwd_mask_tbl);
+ print_string(PRINT_ANY, "group_fwd_mask_str",
+ "group_fwd_mask_str %s ", convbuf);
+ }
+
+ if (tb[IFLA_BRPORT_VLAN_TUNNEL])
+ _print_onoff(f, "vlan_tunnel", "vlan_tunnel",
+ rta_getattr_u8(tb[IFLA_BRPORT_VLAN_TUNNEL]));
+
+ if (tb[IFLA_BRPORT_ISOLATED])
+ _print_onoff(f, "isolated", "isolated",
+ rta_getattr_u8(tb[IFLA_BRPORT_ISOLATED]));
+
+ if (tb[IFLA_BRPORT_BACKUP_PORT]) {
+ int backup_p = rta_getattr_u32(tb[IFLA_BRPORT_BACKUP_PORT]);
+
+ print_string(PRINT_ANY, "backup_port", "backup_port %s ",
+ ll_index_to_name(backup_p));
+ }
}
static void bridge_slave_parse_on_off(char *arg_name, char *arg_val,
NEXT_ARG();
bridge_slave_parse_on_off("neigh_suppress", *argv, n,
IFLA_BRPORT_NEIGH_SUPPRESS);
+ } else if (matches(*argv, "group_fwd_mask") == 0) {
+ __u16 mask;
+
+ NEXT_ARG();
+ if (get_u16(&mask, *argv, 0))
+ invarg("invalid group_fwd_mask", *argv);
+ addattr16(n, 1024, IFLA_BRPORT_GROUP_FWD_MASK, mask);
+ } else if (matches(*argv, "vlan_tunnel") == 0) {
+ NEXT_ARG();
+ bridge_slave_parse_on_off("vlan_tunnel", *argv, n,
+ IFLA_BRPORT_VLAN_TUNNEL);
+ } else if (matches(*argv, "isolated") == 0) {
+ NEXT_ARG();
+ bridge_slave_parse_on_off("isolated", *argv, n,
+ IFLA_BRPORT_ISOLATED);
+ } else if (matches(*argv, "backup_port") == 0) {
+ int ifindex;
+
+ NEXT_ARG();
+ ifindex = ll_name_to_index(*argv);
+ if (!ifindex)
+ invarg("Device does not exist\n", *argv);
+ addattr32(n, 1024, IFLA_BRPORT_BACKUP_PORT, ifindex);
+ } else if (matches(*argv, "nobackup_port") == 0) {
+ addattr32(n, 1024, IFLA_BRPORT_BACKUP_PORT, 0);
} else if (matches(*argv, "help") == 0) {
explain();
return -1;