bridge: fdb get support

This patch adds support to lookup a bridge fdb entry
using recently added support in the kernel using RTM_GETNEIGH
(and AF_BRIDGE family).

example:
$bridge fdb get 02:02:00:00:00:03 dev test-dummy0 vlan 1002
02:02:00:00:00:03 dev test-dummy0 vlan 1002 master bridge

Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
Tested-by: Ivan Vecera <ivecera@redhat.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
Roopa Prabhu 2019-09-30 21:52:22 -07:00 committed by David Ahern
parent 4ecefff3cf
commit 4ed5ad7bd3
2 changed files with 152 additions and 1 deletions

View File

@ -40,7 +40,9 @@ static void usage(void)
" [ sticky ] [ local | static | dynamic ] [ dst IPADDR ]\n" " [ sticky ] [ local | static | dynamic ] [ dst IPADDR ]\n"
" [ vlan VID ] [ port PORT] [ vni VNI ] [ via DEV ]\n" " [ vlan VID ] [ port PORT] [ vni VNI ] [ via DEV ]\n"
" [ src_vni VNI ]\n" " [ src_vni VNI ]\n"
" bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] [ state STATE ] ]\n"); " bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] [ state STATE ] ]\n"
" bridge fdb get ADDR [ br BRDEV ] { brport |dev } DEV [ vlan VID ]\n"
" [ vni VNI ]\n");
exit(-1); exit(-1);
} }
@ -518,6 +520,113 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
return 0; return 0;
} }
static int fdb_get(int argc, char **argv)
{
struct {
struct nlmsghdr n;
struct ndmsg ndm;
char buf[1024];
} req = {
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
.n.nlmsg_flags = NLM_F_REQUEST,
.n.nlmsg_type = RTM_GETNEIGH,
.ndm.ndm_family = AF_BRIDGE,
};
char *d = NULL, *br = NULL;
struct nlmsghdr *answer;
unsigned long vni = ~0;
char abuf[ETH_ALEN];
int br_ifindex = 0;
char *addr = NULL;
short vlan = -1;
char *endptr;
while (argc > 0) {
if ((strcmp(*argv, "brport") == 0) || strcmp(*argv, "dev") == 0) {
NEXT_ARG();
d = *argv;
} else if (strcmp(*argv, "br") == 0) {
NEXT_ARG();
br = *argv;
} else if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
d = *argv;
} else if (strcmp(*argv, "vni") == 0) {
NEXT_ARG();
vni = strtoul(*argv, &endptr, 0);
if ((endptr && *endptr) ||
(vni >> 24) || vni == ULONG_MAX)
invarg("invalid VNI\n", *argv);
} else if (strcmp(*argv, "self") == 0) {
req.ndm.ndm_flags |= NTF_SELF;
} else if (matches(*argv, "master") == 0) {
req.ndm.ndm_flags |= NTF_MASTER;
} else if (matches(*argv, "vlan") == 0) {
if (vlan >= 0)
duparg2("vlan", *argv);
NEXT_ARG();
vlan = atoi(*argv);
} else {
if (strcmp(*argv, "to") == 0)
NEXT_ARG();
if (matches(*argv, "help") == 0)
usage();
if (addr)
duparg2("to", *argv);
addr = *argv;
}
argc--; argv++;
}
if ((d == NULL && br == NULL) || addr == NULL) {
fprintf(stderr, "Device or master and address are required arguments.\n");
return -1;
}
if (sscanf(addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
abuf, abuf+1, abuf+2,
abuf+3, abuf+4, abuf+5) != 6) {
fprintf(stderr, "Invalid mac address %s\n", addr);
return -1;
}
addattr_l(&req.n, sizeof(req), NDA_LLADDR, abuf, ETH_ALEN);
if (vlan >= 0)
addattr16(&req.n, sizeof(req), NDA_VLAN, vlan);
if (vni != ~0)
addattr32(&req.n, sizeof(req), NDA_VNI, vni);
if (d) {
req.ndm.ndm_ifindex = ll_name_to_index(d);
if (!req.ndm.ndm_ifindex) {
fprintf(stderr, "Cannot find device \"%s\"\n", d);
return -1;
}
}
if (br) {
br_ifindex = ll_name_to_index(br);
if (!br_ifindex) {
fprintf(stderr, "Cannot find bridge device \"%s\"\n", br);
return -1;
}
addattr32(&req.n, sizeof(req), NDA_MASTER, br_ifindex);
}
if (rtnl_talk(&rth, &req.n, &answer) < 0)
return -2;
if (print_fdb(answer, stdout) < 0) {
fprintf(stderr, "An error :-)\n");
return -1;
}
return 0;
}
int do_fdb(int argc, char **argv) int do_fdb(int argc, char **argv)
{ {
ll_init_map(&rth); ll_init_map(&rth);
@ -531,6 +640,8 @@ int do_fdb(int argc, char **argv)
return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1); return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
if (matches(*argv, "delete") == 0) if (matches(*argv, "delete") == 0)
return fdb_modify(RTM_DELNEIGH, 0, argc-1, argv+1); return fdb_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
if (matches(*argv, "get") == 0)
return fdb_get(argc-1, argv+1);
if (matches(*argv, "show") == 0 || if (matches(*argv, "show") == 0 ||
matches(*argv, "lst") == 0 || matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0) matches(*argv, "list") == 0)

View File

@ -92,6 +92,17 @@ bridge \- show / manipulate bridge addresses and devices
.B state .B state
.IR STATE " ]" .IR STATE " ]"
.ti -8
.B bridge fdb get
.I LLADDR " [ "
.B dev
.IR DEV " ] [ "
.B br
.IR BRDEV " ] [ "
.B vlan
.IR VID " ] ["
.BR self " ] [ " master " ]"
.ti -8 .ti -8
.BR "bridge mdb" " { " add " | " del " } " .BR "bridge mdb" " { " add " | " del " } "
.B dev .B dev
@ -550,6 +561,35 @@ With the
option, the command becomes verbose. It prints out the last updated option, the command becomes verbose. It prints out the last updated
and last used time for each entry. and last used time for each entry.
.SS bridge fdb get - get bridge forwarding entry.
lookup a bridge forwarding table entry.
.TP
.BI "LLADDR"
the Ethernet MAC address.
.TP
.BI dev " DEV"
the interface to which this address is associated.
.TP
.BI brport " DEV"
the bridge port to which this address is associated. same as dev above.
.TP
.BI br " DEV"
the bridge to which this address is associated.
.TP
.B self
- the address is associated with the port drivers fdb. Usually hardware.
.TP
.B master
- the address is associated with master devices fdb. Usually software (default).
.sp
.SH bridge mdb - multicast group database management .SH bridge mdb - multicast group database management
.B mdb .B mdb