bridge: mdb: add support for source address

This patch adds the user-space control and dump of mdb entry source
address. When setting the new MDBA_SET_ENTRY_ATTRS nested attribute is
used and inside is added MDBE_ATTR_SOURCE based on the address family.
When dumping we look for MDBA_MDB_EATTR_SOURCE and if present we add the
"src x.x.x.x" output. The source address will be always shown as it's
needed to match the entry to modify it from user-space.

Example:
 $ bridge mdb add dev bridge port ens13 grp 239.0.0.1 src 1.2.3.4 permanent vid 100
 $ bridge mdb show
 dev bridge port ens13 grp 239.0.0.1 src 1.2.3.4 permanent vid 100

Signed-off-by: Nikolay Aleksandrov <nikolay@nvidia.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
Nikolay Aleksandrov 2020-10-08 16:50:19 +03:00 committed by David Ahern
parent f905191a48
commit 547b319762
2 changed files with 40 additions and 6 deletions

View File

@ -31,7 +31,7 @@ static unsigned int filter_index, filter_vlan;
static void usage(void) static void usage(void)
{ {
fprintf(stderr, fprintf(stderr,
"Usage: bridge mdb { add | del } dev DEV port PORT grp GROUP [permanent | temp] [vid VID]\n" "Usage: bridge mdb { add | del } dev DEV port PORT grp GROUP [src SOURCE] [permanent | temp] [vid VID]\n"
" bridge mdb {show} [ dev DEV ] [ vid VID ]\n"); " bridge mdb {show} [ dev DEV ] [ vid VID ]\n");
exit(-1); exit(-1);
} }
@ -118,16 +118,16 @@ static void br_print_router_ports(FILE *f, struct rtattr *attr,
static void print_mdb_entry(FILE *f, int ifindex, const 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) struct nlmsghdr *n, struct rtattr **tb)
{ {
const void *grp, *src;
SPRINT_BUF(abuf); SPRINT_BUF(abuf);
const char *dev; const char *dev;
const void *src;
int af; int af;
if (filter_vlan && e->vid != filter_vlan) if (filter_vlan && e->vid != filter_vlan)
return; return;
af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6; af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6;
src = af == AF_INET ? (const void *)&e->addr.u.ip4 : grp = af == AF_INET ? (const void *)&e->addr.u.ip4 :
(const void *)&e->addr.u.ip6; (const void *)&e->addr.u.ip6;
dev = ll_index_to_name(ifindex); dev = ll_index_to_name(ifindex);
@ -140,8 +140,13 @@ static void print_mdb_entry(FILE *f, int ifindex, const struct br_mdb_entry *e,
print_color_string(PRINT_ANY, ifa_family_color(af), print_color_string(PRINT_ANY, ifa_family_color(af),
"grp", " grp %s", "grp", " grp %s",
inet_ntop(af, src, abuf, sizeof(abuf))); inet_ntop(af, grp, abuf, sizeof(abuf)));
if (tb && tb[MDBA_MDB_EATTR_SOURCE]) {
src = (const void *)RTA_DATA(tb[MDBA_MDB_EATTR_SOURCE]);
print_color_string(PRINT_ANY, ifa_family_color(af),
"src", " src %s",
inet_ntop(af, src, abuf, sizeof(abuf)));
}
print_string(PRINT_ANY, "state", " %s", print_string(PRINT_ANY, "state", " %s",
(e->state & MDB_PERMANENT) ? "permanent" : "temp"); (e->state & MDB_PERMANENT) ? "permanent" : "temp");
@ -378,8 +383,8 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
.n.nlmsg_type = cmd, .n.nlmsg_type = cmd,
.bpm.family = PF_BRIDGE, .bpm.family = PF_BRIDGE,
}; };
char *d = NULL, *p = NULL, *grp = NULL, *src = NULL;
struct br_mdb_entry entry = {}; struct br_mdb_entry entry = {};
char *d = NULL, *p = NULL, *grp = NULL;
short vid = 0; short vid = 0;
while (argc > 0) { while (argc > 0) {
@ -400,6 +405,9 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
} else if (strcmp(*argv, "vid") == 0) { } else if (strcmp(*argv, "vid") == 0) {
NEXT_ARG(); NEXT_ARG();
vid = atoi(*argv); vid = atoi(*argv);
} else if (strcmp(*argv, "src") == 0) {
NEXT_ARG();
src = *argv;
} else { } else {
if (matches(*argv, "help") == 0) if (matches(*argv, "help") == 0)
usage(); usage();
@ -431,6 +439,24 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
entry.vid = vid; entry.vid = vid;
addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry)); addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry));
if (src) {
struct rtattr *nest = addattr_nest(&req.n, sizeof(req),
MDBA_SET_ENTRY_ATTRS);
struct in6_addr src_ip6;
__be32 src_ip4;
nest->rta_type |= NLA_F_NESTED;
if (!inet_pton(AF_INET, src, &src_ip4)) {
if (!inet_pton(AF_INET6, src, &src_ip6)) {
fprintf(stderr, "Invalid source address \"%s\"\n", src);
return -1;
}
addattr_l(&req.n, sizeof(req), MDBE_ATTR_SOURCE, &src_ip6, sizeof(src_ip6));
} else {
addattr32(&req.n, sizeof(req), MDBE_ATTR_SOURCE, src_ip4);
}
addattr_nest_end(&req.n, nest);
}
if (rtnl_talk(&rth, &req.n, NULL) < 0) if (rtnl_talk(&rth, &req.n, NULL) < 0)
return -1; return -1;

View File

@ -116,6 +116,8 @@ bridge \- show / manipulate bridge addresses and devices
.I PORT .I PORT
.B grp .B grp
.IR GROUP " [ " .IR GROUP " [ "
.B src
.IR SOURCE " ] [ "
.BR permanent " | " temp " ] [ " .BR permanent " | " temp " ] [ "
.B vid .B vid
.IR VID " ] " .IR VID " ] "
@ -694,6 +696,12 @@ the port.
- the mdb entry is temporary (default) - the mdb entry is temporary (default)
.sp .sp
.TP
.BI src " SOURCE"
optional source IP address of a sender for this multicast group. If IGMPv3 for IPv4, or
MLDv2 for IPv6 respectively, are enabled it will be included in the lookup when
forwarding multicast traffic.
.TP .TP
.BI vid " VID" .BI vid " VID"
the VLAN ID which is known to have members of this multicast group. the VLAN ID which is known to have members of this multicast group.