2017-11-25 04:21:35 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
2012-08-02 06:23:49 +08:00
|
|
|
/*
|
|
|
|
* Get/set/delete fdb table with netlink
|
|
|
|
*
|
2012-10-02 04:58:01 +08:00
|
|
|
* TODO: merge/replace this with ip neighbour
|
|
|
|
*
|
2012-08-02 06:23:49 +08:00
|
|
|
* Authors: Stephen Hemminger <shemminger@vyatta.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
2013-05-01 11:21:22 +08:00
|
|
|
#include <netdb.h>
|
2012-08-02 06:23:49 +08:00
|
|
|
#include <time.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <linux/if_bridge.h>
|
|
|
|
#include <linux/if_ether.h>
|
|
|
|
#include <linux/neighbour.h>
|
|
|
|
#include <string.h>
|
2014-05-27 15:40:10 +08:00
|
|
|
#include <limits.h>
|
bridge: add json support for bridge fdb show
Sample output:
$bridge -j fdb show
[{
"mac": "44:38:39:00:69:88",
"dev": "swp2s0",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "00:02:00:00:00:01",
"dev": "swp2s0",
"vlan": 2,
"master": "br0"
},{
"mac": "00:02:00:00:00:02",
"dev": "swp2s1",
"vlan": 2,
"master": "br0"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:88",
"dev": "br0",
"master": "br0",
"state": "permanent"
}
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
2016-06-22 21:45:53 +08:00
|
|
|
#include <stdbool.h>
|
2012-08-02 06:23:49 +08:00
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
#include "json_print.h"
|
2012-08-02 06:23:49 +08:00
|
|
|
#include "libnetlink.h"
|
|
|
|
#include "br_common.h"
|
2012-10-02 04:58:01 +08:00
|
|
|
#include "rt_names.h"
|
2012-08-02 06:23:49 +08:00
|
|
|
#include "utils.h"
|
|
|
|
|
2020-07-27 21:26:07 +08:00
|
|
|
static unsigned int filter_index, filter_dynamic, filter_master,
|
|
|
|
filter_state, filter_vlan;
|
2012-08-02 06:23:49 +08:00
|
|
|
|
|
|
|
static void usage(void)
|
|
|
|
{
|
2017-10-27 15:15:23 +08:00
|
|
|
fprintf(stderr,
|
|
|
|
"Usage: bridge fdb { add | append | del | replace } ADDR dev DEV\n"
|
2018-03-20 01:20:10 +08:00
|
|
|
" [ self ] [ master ] [ use ] [ router ] [ extern_learn ]\n"
|
2020-06-11 08:35:21 +08:00
|
|
|
" [ sticky ] [ local | static | dynamic ] [ vlan VID ]\n"
|
|
|
|
" { [ dst IPADDR ] [ port PORT] [ vni VNI ] | [ nhid NHID ] }\n"
|
|
|
|
" [ via DEV ] [ src_vni VNI ]\n"
|
2020-07-27 21:26:07 +08:00
|
|
|
" bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ]\n"
|
|
|
|
" [ state STATE ] [ dynamic ] ]\n"
|
|
|
|
" bridge fdb get [ to ] LLADDR [ br BRDEV ] { brport | dev } DEV\n"
|
2022-06-08 20:29:12 +08:00
|
|
|
" [ vlan VID ] [ vni VNI ] [ self ] [ master ] [ dynamic ]\n"
|
2023-10-17 18:55:26 +08:00
|
|
|
" bridge fdb flush dev DEV [ brport DEV ] [ vlan VID ] [ src_vni VNI ]\n"
|
2023-10-17 18:55:30 +08:00
|
|
|
" [ nhid NHID ] [ vni VNI ] [ port PORT ] [ dst IPADDR ] [ self ]\n"
|
|
|
|
" [ master ] [ [no]permanent | [no]static | [no]dynamic ]\n"
|
2022-06-08 20:29:21 +08:00
|
|
|
" [ [no]added_by_user ] [ [no]extern_learn ] [ [no]sticky ]\n"
|
2023-10-17 18:55:31 +08:00
|
|
|
" [ [no]offloaded ] [ [no]router ]\n");
|
2012-08-02 06:23:49 +08:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
2016-03-22 02:56:01 +08:00
|
|
|
static const char *state_n2a(unsigned int s)
|
2012-08-02 06:23:49 +08:00
|
|
|
{
|
|
|
|
static char buf[32];
|
|
|
|
|
2012-10-02 04:58:01 +08:00
|
|
|
if (s & NUD_PERMANENT)
|
|
|
|
return "permanent";
|
2012-08-02 06:23:49 +08:00
|
|
|
|
|
|
|
if (s & NUD_NOARP)
|
|
|
|
return "static";
|
|
|
|
|
|
|
|
if (s & NUD_STALE)
|
|
|
|
return "stale";
|
2012-10-02 04:58:01 +08:00
|
|
|
|
2012-08-02 06:23:49 +08:00
|
|
|
if (s & NUD_REACHABLE)
|
|
|
|
return "";
|
|
|
|
|
2020-07-29 21:04:25 +08:00
|
|
|
if (is_json_context())
|
|
|
|
sprintf(buf, "%#x", s);
|
|
|
|
else
|
|
|
|
sprintf(buf, "state=%#x", s);
|
2012-08-02 06:23:49 +08:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2017-01-13 00:47:39 +08:00
|
|
|
static int state_a2n(unsigned int *s, const char *arg)
|
|
|
|
{
|
|
|
|
if (matches(arg, "permanent") == 0)
|
|
|
|
*s = NUD_PERMANENT;
|
|
|
|
else if (matches(arg, "static") == 0 || matches(arg, "temp") == 0)
|
|
|
|
*s = NUD_NOARP;
|
|
|
|
else if (matches(arg, "stale") == 0)
|
|
|
|
*s = NUD_STALE;
|
|
|
|
else if (matches(arg, "reachable") == 0 || matches(arg, "dynamic") == 0)
|
|
|
|
*s = NUD_REACHABLE;
|
|
|
|
else if (strcmp(arg, "all") == 0)
|
|
|
|
*s = ~0;
|
|
|
|
else if (get_unsigned(s, arg, 0))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-11-06 19:39:55 +08:00
|
|
|
static void fdb_print_flags(FILE *fp, unsigned int flags, __u32 ext_flags)
|
2018-02-21 03:24:05 +08:00
|
|
|
{
|
|
|
|
open_json_array(PRINT_JSON,
|
|
|
|
is_json_context() ? "flags" : "");
|
|
|
|
|
|
|
|
if (flags & NTF_SELF)
|
|
|
|
print_string(PRINT_ANY, NULL, "%s ", "self");
|
|
|
|
|
|
|
|
if (flags & NTF_ROUTER)
|
|
|
|
print_string(PRINT_ANY, NULL, "%s ", "router");
|
|
|
|
|
|
|
|
if (flags & NTF_EXT_LEARNED)
|
|
|
|
print_string(PRINT_ANY, NULL, "%s ", "extern_learn");
|
|
|
|
|
|
|
|
if (flags & NTF_OFFLOADED)
|
|
|
|
print_string(PRINT_ANY, NULL, "%s ", "offload");
|
|
|
|
|
|
|
|
if (flags & NTF_MASTER)
|
|
|
|
print_string(PRINT_ANY, NULL, "%s ", "master");
|
|
|
|
|
2018-09-27 21:35:12 +08:00
|
|
|
if (flags & NTF_STICKY)
|
|
|
|
print_string(PRINT_ANY, NULL, "%s ", "sticky");
|
|
|
|
|
2022-11-06 19:39:55 +08:00
|
|
|
if (ext_flags & NTF_EXT_LOCKED)
|
|
|
|
print_string(PRINT_ANY, NULL, "%s ", "locked");
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
close_json_array(PRINT_JSON, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fdb_print_stats(FILE *fp, const struct nda_cacheinfo *ci)
|
bridge: add json support for bridge fdb show
Sample output:
$bridge -j fdb show
[{
"mac": "44:38:39:00:69:88",
"dev": "swp2s0",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "00:02:00:00:00:01",
"dev": "swp2s0",
"vlan": 2,
"master": "br0"
},{
"mac": "00:02:00:00:00:02",
"dev": "swp2s1",
"vlan": 2,
"master": "br0"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:88",
"dev": "br0",
"master": "br0",
"state": "permanent"
}
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
2016-06-22 21:45:53 +08:00
|
|
|
{
|
2018-02-21 03:24:05 +08:00
|
|
|
static int hz;
|
|
|
|
|
|
|
|
if (!hz)
|
|
|
|
hz = get_user_hz();
|
|
|
|
|
|
|
|
if (is_json_context()) {
|
|
|
|
print_uint(PRINT_JSON, "used", NULL,
|
|
|
|
ci->ndm_used / hz);
|
|
|
|
print_uint(PRINT_JSON, "updated", NULL,
|
|
|
|
ci->ndm_updated / hz);
|
|
|
|
} else {
|
|
|
|
fprintf(fp, "used %d/%d ", ci->ndm_used / hz,
|
|
|
|
ci->ndm_updated / hz);
|
|
|
|
|
|
|
|
}
|
bridge: add json support for bridge fdb show
Sample output:
$bridge -j fdb show
[{
"mac": "44:38:39:00:69:88",
"dev": "swp2s0",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "00:02:00:00:00:01",
"dev": "swp2s0",
"vlan": 2,
"master": "br0"
},{
"mac": "00:02:00:00:00:02",
"dev": "swp2s1",
"vlan": 2,
"master": "br0"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:88",
"dev": "br0",
"master": "br0",
"state": "permanent"
}
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
2016-06-22 21:45:53 +08:00
|
|
|
}
|
|
|
|
|
2018-10-20 04:42:36 +08:00
|
|
|
int print_fdb(struct nlmsghdr *n, void *arg)
|
2012-08-02 06:23:49 +08:00
|
|
|
{
|
2012-10-02 04:58:01 +08:00
|
|
|
FILE *fp = arg;
|
2012-08-02 06:23:49 +08:00
|
|
|
struct ndmsg *r = NLMSG_DATA(n);
|
|
|
|
int len = n->nlmsg_len;
|
2016-03-22 02:56:01 +08:00
|
|
|
struct rtattr *tb[NDA_MAX+1];
|
2022-11-06 19:39:55 +08:00
|
|
|
__u32 ext_flags = 0;
|
2016-04-11 23:45:14 +08:00
|
|
|
__u16 vid = 0;
|
2012-10-02 04:58:01 +08:00
|
|
|
|
|
|
|
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
|
|
|
|
fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
|
|
|
|
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
|
|
|
|
return 0;
|
|
|
|
}
|
2012-08-02 06:23:49 +08:00
|
|
|
|
|
|
|
len -= NLMSG_LENGTH(sizeof(*r));
|
|
|
|
if (len < 0) {
|
|
|
|
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r->ndm_family != AF_BRIDGE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (filter_index && filter_index != r->ndm_ifindex)
|
|
|
|
return 0;
|
|
|
|
|
2017-01-13 00:47:39 +08:00
|
|
|
if (filter_state && !(r->ndm_state & filter_state))
|
|
|
|
return 0;
|
|
|
|
|
2012-08-02 06:23:49 +08:00
|
|
|
parse_rtattr(tb, NDA_MAX, NDA_RTA(r),
|
|
|
|
n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
|
|
|
|
|
2022-11-06 19:39:55 +08:00
|
|
|
if (tb[NDA_FLAGS_EXT])
|
|
|
|
ext_flags = rta_getattr_u32(tb[NDA_FLAGS_EXT]);
|
|
|
|
|
2016-04-11 23:45:14 +08:00
|
|
|
if (tb[NDA_VLAN])
|
|
|
|
vid = rta_getattr_u16(tb[NDA_VLAN]);
|
|
|
|
|
|
|
|
if (filter_vlan && filter_vlan != vid)
|
|
|
|
return 0;
|
|
|
|
|
2020-07-27 21:26:07 +08:00
|
|
|
if (filter_dynamic && (r->ndm_state & NUD_PERMANENT))
|
|
|
|
return 0;
|
|
|
|
|
2022-09-22 14:19:35 +08:00
|
|
|
print_headers(fp, "[NEIGH]");
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
open_json_object(NULL);
|
|
|
|
if (n->nlmsg_type == RTM_DELNEIGH)
|
|
|
|
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
|
2012-10-02 04:58:01 +08:00
|
|
|
|
|
|
|
if (tb[NDA_LLADDR]) {
|
2018-02-21 03:24:05 +08:00
|
|
|
const char *lladdr;
|
2012-10-02 04:58:01 +08:00
|
|
|
SPRINT_BUF(b1);
|
2018-02-21 03:24:05 +08:00
|
|
|
|
|
|
|
lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
|
|
|
|
RTA_PAYLOAD(tb[NDA_LLADDR]),
|
|
|
|
ll_index_to_type(r->ndm_ifindex),
|
|
|
|
b1, sizeof(b1));
|
|
|
|
|
|
|
|
print_color_string(PRINT_ANY, COLOR_MAC,
|
|
|
|
"mac", "%s ", lladdr);
|
2012-08-02 06:23:49 +08:00
|
|
|
}
|
2012-10-30 08:48:55 +08:00
|
|
|
|
2021-08-18 01:28:06 +08:00
|
|
|
if (!filter_index && r->ndm_ifindex) {
|
|
|
|
print_string(PRINT_FP, NULL, "dev ", NULL);
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
print_color_string(PRINT_ANY, COLOR_IFNAME,
|
2021-08-18 01:28:06 +08:00
|
|
|
"ifname", "%s ",
|
2018-02-21 03:24:05 +08:00
|
|
|
ll_index_to_name(r->ndm_ifindex));
|
2021-08-18 01:28:06 +08:00
|
|
|
}
|
2012-10-02 04:58:01 +08:00
|
|
|
|
|
|
|
if (tb[NDA_DST]) {
|
2014-03-20 19:06:10 +08:00
|
|
|
int family = AF_INET;
|
2018-02-21 03:24:05 +08:00
|
|
|
const char *dst;
|
2014-03-20 19:06:10 +08:00
|
|
|
|
|
|
|
if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
|
|
|
|
family = AF_INET6;
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
dst = format_host(family,
|
|
|
|
RTA_PAYLOAD(tb[NDA_DST]),
|
|
|
|
RTA_DATA(tb[NDA_DST]));
|
bridge: add json support for bridge fdb show
Sample output:
$bridge -j fdb show
[{
"mac": "44:38:39:00:69:88",
"dev": "swp2s0",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "00:02:00:00:00:01",
"dev": "swp2s0",
"vlan": 2,
"master": "br0"
},{
"mac": "00:02:00:00:00:02",
"dev": "swp2s1",
"vlan": 2,
"master": "br0"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:88",
"dev": "br0",
"master": "br0",
"state": "permanent"
}
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
2016-06-22 21:45:53 +08:00
|
|
|
|
2021-08-18 01:28:06 +08:00
|
|
|
print_string(PRINT_FP, NULL, "dst ", NULL);
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
print_color_string(PRINT_ANY,
|
|
|
|
ifa_family_color(family),
|
2021-08-18 01:28:06 +08:00
|
|
|
"dst", "%s ", dst);
|
bridge: add json support for bridge fdb show
Sample output:
$bridge -j fdb show
[{
"mac": "44:38:39:00:69:88",
"dev": "swp2s0",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "00:02:00:00:00:01",
"dev": "swp2s0",
"vlan": 2,
"master": "br0"
},{
"mac": "00:02:00:00:00:02",
"dev": "swp2s1",
"vlan": 2,
"master": "br0"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:88",
"dev": "br0",
"master": "br0",
"state": "permanent"
}
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
2016-06-22 21:45:53 +08:00
|
|
|
}
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
if (vid)
|
|
|
|
print_uint(PRINT_ANY,
|
|
|
|
"vlan", "vlan %hu ", vid);
|
2012-10-30 08:48:55 +08:00
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
if (tb[NDA_PORT])
|
|
|
|
print_uint(PRINT_ANY,
|
|
|
|
"port", "port %u ",
|
|
|
|
rta_getattr_be16(tb[NDA_PORT]));
|
2013-02-28 18:04:04 +08:00
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
if (tb[NDA_VNI])
|
|
|
|
print_uint(PRINT_ANY,
|
|
|
|
"vni", "vni %u ",
|
|
|
|
rta_getattr_u32(tb[NDA_VNI]));
|
|
|
|
|
|
|
|
if (tb[NDA_SRC_VNI])
|
|
|
|
print_uint(PRINT_ANY,
|
|
|
|
"src_vni", "src_vni %u ",
|
2017-10-27 01:12:55 +08:00
|
|
|
rta_getattr_u32(tb[NDA_SRC_VNI]));
|
|
|
|
|
2013-05-01 11:21:22 +08:00
|
|
|
if (tb[NDA_IFINDEX]) {
|
|
|
|
unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]);
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
if (tb[NDA_LINK_NETNSID])
|
|
|
|
print_uint(PRINT_ANY,
|
|
|
|
"viaIfIndex", "via ifindex %u ",
|
|
|
|
ifindex);
|
bridge: add json support for bridge fdb show
Sample output:
$bridge -j fdb show
[{
"mac": "44:38:39:00:69:88",
"dev": "swp2s0",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "00:02:00:00:00:01",
"dev": "swp2s0",
"vlan": 2,
"master": "br0"
},{
"mac": "00:02:00:00:00:02",
"dev": "swp2s1",
"vlan": 2,
"master": "br0"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:88",
"dev": "br0",
"master": "br0",
"state": "permanent"
}
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
2016-06-22 21:45:53 +08:00
|
|
|
else
|
2018-02-21 03:24:05 +08:00
|
|
|
print_string(PRINT_ANY,
|
|
|
|
"viaIf", "via %s ",
|
|
|
|
ll_index_to_name(ifindex));
|
bridge: add json support for bridge fdb show
Sample output:
$bridge -j fdb show
[{
"mac": "44:38:39:00:69:88",
"dev": "swp2s0",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "00:02:00:00:00:01",
"dev": "swp2s0",
"vlan": 2,
"master": "br0"
},{
"mac": "00:02:00:00:00:02",
"dev": "swp2s1",
"vlan": 2,
"master": "br0"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:88",
"dev": "br0",
"master": "br0",
"state": "permanent"
}
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
2016-06-22 21:45:53 +08:00
|
|
|
}
|
2013-05-01 11:21:22 +08:00
|
|
|
|
2020-06-11 08:35:21 +08:00
|
|
|
if (tb[NDA_NH_ID])
|
|
|
|
print_uint(PRINT_ANY, "nhid", "nhid %u ",
|
|
|
|
rta_getattr_u32(tb[NDA_NH_ID]));
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
if (tb[NDA_LINK_NETNSID])
|
|
|
|
print_uint(PRINT_ANY,
|
|
|
|
"linkNetNsId", "link-netnsid %d ",
|
|
|
|
rta_getattr_u32(tb[NDA_LINK_NETNSID]));
|
2012-08-02 06:23:49 +08:00
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
if (show_stats && tb[NDA_CACHEINFO])
|
|
|
|
fdb_print_stats(fp, RTA_DATA(tb[NDA_CACHEINFO]));
|
bridge: add json support for bridge fdb show
Sample output:
$bridge -j fdb show
[{
"mac": "44:38:39:00:69:88",
"dev": "swp2s0",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "00:02:00:00:00:01",
"dev": "swp2s0",
"vlan": 2,
"master": "br0"
},{
"mac": "00:02:00:00:00:02",
"dev": "swp2s1",
"vlan": 2,
"master": "br0"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:88",
"dev": "br0",
"master": "br0",
"state": "permanent"
}
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
2016-06-22 21:45:53 +08:00
|
|
|
|
2022-11-06 19:39:55 +08:00
|
|
|
fdb_print_flags(fp, r->ndm_flags, ext_flags);
|
bridge: add json support for bridge fdb show
Sample output:
$bridge -j fdb show
[{
"mac": "44:38:39:00:69:88",
"dev": "swp2s0",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "00:02:00:00:00:01",
"dev": "swp2s0",
"vlan": 2,
"master": "br0"
},{
"mac": "00:02:00:00:00:02",
"dev": "swp2s1",
"vlan": 2,
"master": "br0"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:89",
"dev": "swp2s1",
"vlan": 2,
"master": "br0",
"state": "permanent"
},{
"mac": "44:38:39:00:69:88",
"dev": "br0",
"master": "br0",
"state": "permanent"
}
]
Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
2016-06-22 21:45:53 +08:00
|
|
|
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
if (tb[NDA_MASTER])
|
2018-10-09 20:44:08 +08:00
|
|
|
print_string(PRINT_ANY, "master", "master %s ",
|
2018-02-21 03:24:05 +08:00
|
|
|
ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
|
2015-10-16 05:53:17 +08:00
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
print_string(PRINT_ANY, "state", "%s\n",
|
|
|
|
state_n2a(r->ndm_state));
|
|
|
|
close_json_object();
|
|
|
|
fflush(fp);
|
2012-08-02 06:23:49 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-03 08:33:42 +08:00
|
|
|
static int fdb_linkdump_filter(struct nlmsghdr *nlh, int reqlen)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (filter_index) {
|
|
|
|
struct ifinfomsg *ifm = NLMSG_DATA(nlh);
|
|
|
|
|
|
|
|
ifm->ifi_index = filter_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filter_master) {
|
|
|
|
err = addattr32(nlh, reqlen, IFLA_MASTER, filter_master);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-01 02:00:24 +08:00
|
|
|
static int fdb_dump_filter(struct nlmsghdr *nlh, int reqlen)
|
2012-08-02 06:23:49 +08:00
|
|
|
{
|
2019-01-01 02:00:24 +08:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (filter_index) {
|
|
|
|
struct ndmsg *ndm = NLMSG_DATA(nlh);
|
2014-07-04 20:37:10 +08:00
|
|
|
|
2019-01-01 02:00:24 +08:00
|
|
|
ndm->ndm_ifindex = filter_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filter_master) {
|
|
|
|
err = addattr32(nlh, reqlen, NDA_MASTER, filter_master);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fdb_show(int argc, char **argv)
|
|
|
|
{
|
2012-08-02 06:23:49 +08:00
|
|
|
char *filter_dev = NULL;
|
2014-07-04 20:37:10 +08:00
|
|
|
char *br = NULL;
|
2019-01-03 08:33:42 +08:00
|
|
|
int rc;
|
2014-07-04 20:37:10 +08:00
|
|
|
|
2012-08-02 06:23:49 +08:00
|
|
|
while (argc > 0) {
|
2014-07-04 20:37:10 +08:00
|
|
|
if ((strcmp(*argv, "brport") == 0) || strcmp(*argv, "dev") == 0) {
|
2012-08-02 06:23:49 +08:00
|
|
|
NEXT_ARG();
|
|
|
|
filter_dev = *argv;
|
2014-07-04 20:37:10 +08:00
|
|
|
} else if (strcmp(*argv, "br") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
br = *argv;
|
2016-04-11 23:45:14 +08:00
|
|
|
} else if (strcmp(*argv, "vlan") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
if (filter_vlan)
|
|
|
|
duparg("vlan", *argv);
|
|
|
|
filter_vlan = atoi(*argv);
|
2017-01-13 00:47:39 +08:00
|
|
|
} else if (strcmp(*argv, "state") == 0) {
|
|
|
|
unsigned int state;
|
|
|
|
|
|
|
|
NEXT_ARG();
|
|
|
|
if (state_a2n(&state, *argv))
|
|
|
|
invarg("invalid state", *argv);
|
|
|
|
filter_state |= state;
|
2020-07-27 21:26:07 +08:00
|
|
|
} else if (strcmp(*argv, "dynamic") == 0) {
|
|
|
|
filter_dynamic = 1;
|
2014-07-04 20:37:10 +08:00
|
|
|
} else {
|
|
|
|
if (matches(*argv, "help") == 0)
|
|
|
|
usage();
|
2012-08-02 06:23:49 +08:00
|
|
|
}
|
|
|
|
argc--; argv++;
|
|
|
|
}
|
|
|
|
|
2014-07-04 20:37:10 +08:00
|
|
|
if (br) {
|
|
|
|
int br_ifindex = ll_name_to_index(br);
|
2016-03-22 02:56:01 +08:00
|
|
|
|
2014-07-04 20:37:10 +08:00
|
|
|
if (br_ifindex == 0) {
|
|
|
|
fprintf(stderr, "Cannot find bridge device \"%s\"\n", br);
|
|
|
|
return -1;
|
|
|
|
}
|
2019-01-01 02:00:24 +08:00
|
|
|
filter_master = br_ifindex;
|
2014-07-04 20:37:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*we'll keep around filter_dev for older kernels */
|
2012-08-02 06:23:49 +08:00
|
|
|
if (filter_dev) {
|
2018-01-20 00:44:03 +08:00
|
|
|
filter_index = ll_name_to_index(filter_dev);
|
2018-03-07 16:40:36 +08:00
|
|
|
if (!filter_index)
|
|
|
|
return nodev(filter_dev);
|
2012-08-02 06:23:49 +08:00
|
|
|
}
|
|
|
|
|
2019-01-03 08:33:42 +08:00
|
|
|
if (rth.flags & RTNL_HANDLE_F_STRICT_CHK)
|
|
|
|
rc = rtnl_neighdump_req(&rth, PF_BRIDGE, fdb_dump_filter);
|
|
|
|
else
|
2019-01-26 01:09:17 +08:00
|
|
|
rc = rtnl_fdb_linkdump_req_filter_fn(&rth, fdb_linkdump_filter);
|
2019-01-03 08:33:42 +08:00
|
|
|
if (rc < 0) {
|
2012-08-02 06:23:49 +08:00
|
|
|
perror("Cannot send dump request");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
new_json_obj(json);
|
2012-10-02 04:58:01 +08:00
|
|
|
if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) {
|
2012-08-02 06:23:49 +08:00
|
|
|
fprintf(stderr, "Dump terminated\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2018-02-21 03:24:05 +08:00
|
|
|
delete_json_obj();
|
|
|
|
fflush(stdout);
|
2012-08-02 06:23:49 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fdb_modify(int cmd, int flags, int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct {
|
2016-03-22 02:56:01 +08:00
|
|
|
struct nlmsghdr n;
|
|
|
|
struct ndmsg ndm;
|
|
|
|
char buf[256];
|
2016-07-18 22:48:42 +08:00
|
|
|
} req = {
|
|
|
|
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
|
|
|
|
.n.nlmsg_flags = NLM_F_REQUEST | flags,
|
|
|
|
.n.nlmsg_type = cmd,
|
|
|
|
.ndm.ndm_family = PF_BRIDGE,
|
|
|
|
.ndm.ndm_state = NUD_NOARP,
|
|
|
|
};
|
2012-08-02 06:23:49 +08:00
|
|
|
char *addr = NULL;
|
|
|
|
char *d = NULL;
|
|
|
|
char abuf[ETH_ALEN];
|
2012-10-02 04:58:01 +08:00
|
|
|
int dst_ok = 0;
|
|
|
|
inet_prefix dst;
|
2013-05-01 11:21:22 +08:00
|
|
|
unsigned long port = 0;
|
|
|
|
unsigned long vni = ~0;
|
2019-03-04 13:26:32 +08:00
|
|
|
unsigned long src_vni = ~0;
|
2013-05-01 11:21:22 +08:00
|
|
|
unsigned int via = 0;
|
|
|
|
char *endptr;
|
2013-02-28 18:04:04 +08:00
|
|
|
short vid = -1;
|
2020-06-11 08:35:21 +08:00
|
|
|
__u32 nhid = 0;
|
2012-08-02 06:23:49 +08:00
|
|
|
|
|
|
|
while (argc > 0) {
|
|
|
|
if (strcmp(*argv, "dev") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
d = *argv;
|
2012-10-02 04:58:01 +08:00
|
|
|
} else if (strcmp(*argv, "dst") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
if (dst_ok)
|
|
|
|
duparg2("dst", *argv);
|
|
|
|
get_addr(&dst, *argv, preferred_family);
|
|
|
|
dst_ok = 1;
|
2020-06-11 08:35:21 +08:00
|
|
|
} else if (strcmp(*argv, "nhid") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
if (get_u32(&nhid, *argv, 0))
|
|
|
|
invarg("\"id\" value is invalid\n", *argv);
|
2013-05-01 11:21:22 +08:00
|
|
|
} else if (strcmp(*argv, "port") == 0) {
|
|
|
|
|
|
|
|
NEXT_ARG();
|
|
|
|
port = strtoul(*argv, &endptr, 0);
|
|
|
|
if (endptr && *endptr) {
|
|
|
|
struct servent *pse;
|
|
|
|
|
|
|
|
pse = getservbyname(*argv, "udp");
|
|
|
|
if (!pse)
|
|
|
|
invarg("invalid port\n", *argv);
|
|
|
|
port = ntohs(pse->s_port);
|
|
|
|
} else if (port > 0xffff)
|
|
|
|
invarg("invalid port\n", *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);
|
2019-03-04 13:26:32 +08:00
|
|
|
} else if (strcmp(*argv, "src_vni") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
src_vni = strtoul(*argv, &endptr, 0);
|
|
|
|
if ((endptr && *endptr) ||
|
|
|
|
(src_vni >> 24) || src_vni == ULONG_MAX)
|
|
|
|
invarg("invalid src VNI\n", *argv);
|
2013-05-01 11:21:22 +08:00
|
|
|
} else if (strcmp(*argv, "via") == 0) {
|
|
|
|
NEXT_ARG();
|
2018-01-20 00:44:03 +08:00
|
|
|
via = ll_name_to_index(*argv);
|
2018-03-07 16:40:36 +08:00
|
|
|
if (!via)
|
|
|
|
exit(nodev(*argv));
|
2012-08-24 04:37:19 +08:00
|
|
|
} else if (strcmp(*argv, "self") == 0) {
|
|
|
|
req.ndm.ndm_flags |= NTF_SELF;
|
2012-10-02 04:58:01 +08:00
|
|
|
} else if (matches(*argv, "master") == 0) {
|
2012-08-24 04:37:19 +08:00
|
|
|
req.ndm.ndm_flags |= NTF_MASTER;
|
2013-05-06 20:11:46 +08:00
|
|
|
} else if (matches(*argv, "router") == 0) {
|
|
|
|
req.ndm.ndm_flags |= NTF_ROUTER;
|
2016-03-28 01:47:46 +08:00
|
|
|
} else if (matches(*argv, "local") == 0 ||
|
2012-10-02 04:58:01 +08:00
|
|
|
matches(*argv, "permanent") == 0) {
|
|
|
|
req.ndm.ndm_state |= NUD_PERMANENT;
|
2016-01-28 01:09:37 +08:00
|
|
|
} else if (matches(*argv, "temp") == 0 ||
|
|
|
|
matches(*argv, "static") == 0) {
|
2012-10-02 04:58:01 +08:00
|
|
|
req.ndm.ndm_state |= NUD_REACHABLE;
|
2016-02-20 13:34:52 +08:00
|
|
|
} else if (matches(*argv, "dynamic") == 0) {
|
|
|
|
req.ndm.ndm_state |= NUD_REACHABLE;
|
|
|
|
req.ndm.ndm_state &= ~NUD_NOARP;
|
2013-02-28 18:04:04 +08:00
|
|
|
} else if (matches(*argv, "vlan") == 0) {
|
|
|
|
if (vid >= 0)
|
|
|
|
duparg2("vlan", *argv);
|
|
|
|
NEXT_ARG();
|
|
|
|
vid = atoi(*argv);
|
2015-07-31 05:37:02 +08:00
|
|
|
} else if (matches(*argv, "use") == 0) {
|
|
|
|
req.ndm.ndm_flags |= NTF_USE;
|
2018-03-20 01:20:10 +08:00
|
|
|
} else if (matches(*argv, "extern_learn") == 0) {
|
|
|
|
req.ndm.ndm_flags |= NTF_EXT_LEARNED;
|
2018-09-27 21:35:12 +08:00
|
|
|
} else if (matches(*argv, "sticky") == 0) {
|
|
|
|
req.ndm.ndm_flags |= NTF_STICKY;
|
2012-08-02 06:23:49 +08:00
|
|
|
} else {
|
2017-10-27 15:15:23 +08:00
|
|
|
if (strcmp(*argv, "to") == 0)
|
2012-08-02 06:23:49 +08:00
|
|
|
NEXT_ARG();
|
2017-10-27 15:15:23 +08:00
|
|
|
|
2012-10-02 04:58:01 +08:00
|
|
|
if (matches(*argv, "help") == 0)
|
|
|
|
usage();
|
2012-08-02 06:23:49 +08:00
|
|
|
if (addr)
|
|
|
|
duparg2("to", *argv);
|
|
|
|
addr = *argv;
|
|
|
|
}
|
|
|
|
argc--; argv++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d == NULL || addr == NULL) {
|
|
|
|
fprintf(stderr, "Device and address are required arguments.\n");
|
2015-03-18 10:26:32 +08:00
|
|
|
return -1;
|
2012-08-02 06:23:49 +08:00
|
|
|
}
|
|
|
|
|
2020-06-11 08:35:21 +08:00
|
|
|
if (nhid && (dst_ok || port || vni != ~0)) {
|
|
|
|
fprintf(stderr, "dst, port, vni are mutually exclusive with nhid\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-10-02 04:58:01 +08:00
|
|
|
/* Assume self */
|
|
|
|
if (!(req.ndm.ndm_flags&(NTF_SELF|NTF_MASTER)))
|
|
|
|
req.ndm.ndm_flags |= NTF_SELF;
|
|
|
|
|
|
|
|
/* Assume permanent */
|
|
|
|
if (!(req.ndm.ndm_state&(NUD_PERMANENT|NUD_REACHABLE)))
|
|
|
|
req.ndm.ndm_state |= NUD_PERMANENT;
|
|
|
|
|
|
|
|
if (sscanf(addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
2012-08-02 06:23:49 +08:00
|
|
|
abuf, abuf+1, abuf+2,
|
|
|
|
abuf+3, abuf+4, abuf+5) != 6) {
|
|
|
|
fprintf(stderr, "Invalid mac address %s\n", addr);
|
2015-03-18 10:26:32 +08:00
|
|
|
return -1;
|
2012-08-02 06:23:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
addattr_l(&req.n, sizeof(req), NDA_LLADDR, abuf, ETH_ALEN);
|
2012-10-02 04:58:01 +08:00
|
|
|
if (dst_ok)
|
|
|
|
addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen);
|
2012-08-02 06:23:49 +08:00
|
|
|
|
2013-02-28 18:04:04 +08:00
|
|
|
if (vid >= 0)
|
2013-03-07 03:04:29 +08:00
|
|
|
addattr16(&req.n, sizeof(req), NDA_VLAN, vid);
|
2020-06-11 08:35:21 +08:00
|
|
|
if (nhid > 0)
|
|
|
|
addattr32(&req.n, sizeof(req), NDA_NH_ID, nhid);
|
2013-02-28 18:04:04 +08:00
|
|
|
|
2013-05-01 11:21:22 +08:00
|
|
|
if (port) {
|
|
|
|
unsigned short dport;
|
|
|
|
|
|
|
|
dport = htons((unsigned short)port);
|
|
|
|
addattr16(&req.n, sizeof(req), NDA_PORT, dport);
|
|
|
|
}
|
|
|
|
if (vni != ~0)
|
|
|
|
addattr32(&req.n, sizeof(req), NDA_VNI, vni);
|
2019-03-04 13:26:32 +08:00
|
|
|
if (src_vni != ~0)
|
|
|
|
addattr32(&req.n, sizeof(req), NDA_SRC_VNI, src_vni);
|
2013-05-01 11:21:22 +08:00
|
|
|
if (via)
|
|
|
|
addattr32(&req.n, sizeof(req), NDA_IFINDEX, via);
|
|
|
|
|
2012-08-02 06:23:49 +08:00
|
|
|
req.ndm.ndm_ifindex = ll_name_to_index(d);
|
2018-03-07 16:40:36 +08:00
|
|
|
if (!req.ndm.ndm_ifindex)
|
|
|
|
return nodev(d);
|
2012-08-02 06:23:49 +08:00
|
|
|
|
lib/libnetlink: update rtnl_talk to support malloc buff at run time
This is an update for 460c03f3f3cc ("iplink: double the buffer size also in
iplink_get()"). After update, we will not need to double the buffer size
every time when VFs number increased.
With call like rtnl_talk(&rth, &req.n, NULL, 0), we can simply remove the
length parameter.
With call like rtnl_talk(&rth, nlh, nlh, sizeof(req), I add a new variable
answer to avoid overwrite data in nlh, because it may has more info after
nlh. also this will avoid nlh buffer not enough issue.
We need to free answer after using.
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Signed-off-by: Phil Sutter <phil@nwl.cc>
2017-10-26 09:41:47 +08:00
|
|
|
if (rtnl_talk(&rth, &req.n, NULL) < 0)
|
2015-03-18 10:26:32 +08:00
|
|
|
return -1;
|
2012-08-02 06:23:49 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-01 12:52:22 +08:00
|
|
|
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;
|
2022-07-11 07:52:51 +08:00
|
|
|
int ret;
|
2019-10-01 12:52:22 +08:00
|
|
|
|
|
|
|
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);
|
2020-07-27 21:26:07 +08:00
|
|
|
} else if (matches(*argv, "dynamic") == 0) {
|
|
|
|
filter_dynamic = 1;
|
2019-10-01 12:52:22 +08:00
|
|
|
} 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;
|
|
|
|
|
2020-07-10 08:53:02 +08:00
|
|
|
/*
|
|
|
|
* Initialize a json_writer and open an array object
|
|
|
|
* if -json was specified.
|
|
|
|
*/
|
|
|
|
new_json_obj(json);
|
2022-07-11 07:52:51 +08:00
|
|
|
ret = 0;
|
2019-10-01 12:52:22 +08:00
|
|
|
if (print_fdb(answer, stdout) < 0) {
|
|
|
|
fprintf(stderr, "An error :-)\n");
|
2022-07-11 07:52:51 +08:00
|
|
|
ret = -1;
|
2019-10-01 12:52:22 +08:00
|
|
|
}
|
2020-07-10 08:53:02 +08:00
|
|
|
delete_json_obj();
|
2022-07-11 07:52:51 +08:00
|
|
|
free(answer);
|
2019-10-01 12:52:22 +08:00
|
|
|
|
2022-07-11 07:52:51 +08:00
|
|
|
return ret;
|
2019-10-01 12:52:22 +08:00
|
|
|
}
|
|
|
|
|
2022-06-08 20:29:12 +08:00
|
|
|
static int fdb_flush(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct {
|
|
|
|
struct nlmsghdr n;
|
|
|
|
struct ndmsg ndm;
|
|
|
|
char buf[256];
|
|
|
|
} req = {
|
|
|
|
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
|
|
|
|
.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_BULK,
|
|
|
|
.n.nlmsg_type = RTM_DELNEIGH,
|
|
|
|
.ndm.ndm_family = PF_BRIDGE,
|
|
|
|
};
|
2022-06-08 20:29:15 +08:00
|
|
|
unsigned short ndm_state_mask = 0;
|
2022-06-08 20:29:18 +08:00
|
|
|
unsigned short ndm_flags_mask = 0;
|
2023-10-17 18:55:25 +08:00
|
|
|
short vid = -1, brport_ifidx = -1;
|
|
|
|
char *d = NULL, *brport = NULL;
|
2022-06-08 20:29:12 +08:00
|
|
|
unsigned short ndm_flags = 0;
|
2022-06-08 20:29:15 +08:00
|
|
|
unsigned short ndm_state = 0;
|
2023-10-17 18:55:26 +08:00
|
|
|
unsigned long src_vni = ~0;
|
2023-10-17 18:55:28 +08:00
|
|
|
unsigned long vni = ~0;
|
2023-10-17 18:55:29 +08:00
|
|
|
unsigned long port = 0;
|
2023-10-17 18:55:30 +08:00
|
|
|
inet_prefix dst;
|
|
|
|
int dst_ok = 0;
|
2023-10-17 18:55:27 +08:00
|
|
|
__u32 nhid = 0;
|
2023-10-17 18:55:26 +08:00
|
|
|
char *endptr;
|
2022-06-08 20:29:12 +08:00
|
|
|
|
|
|
|
while (argc > 0) {
|
|
|
|
if (strcmp(*argv, "dev") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
d = *argv;
|
|
|
|
} else if (strcmp(*argv, "master") == 0) {
|
|
|
|
ndm_flags |= NTF_MASTER;
|
|
|
|
} else if (strcmp(*argv, "self") == 0) {
|
|
|
|
ndm_flags |= NTF_SELF;
|
2022-06-08 20:29:15 +08:00
|
|
|
} else if (strcmp(*argv, "permanent") == 0) {
|
|
|
|
ndm_state |= NUD_PERMANENT;
|
|
|
|
ndm_state_mask |= NUD_PERMANENT;
|
|
|
|
} else if (strcmp(*argv, "nopermanent") == 0) {
|
|
|
|
ndm_state &= ~NUD_PERMANENT;
|
|
|
|
ndm_state_mask |= NUD_PERMANENT;
|
2022-06-08 20:29:16 +08:00
|
|
|
} else if (strcmp(*argv, "static") == 0) {
|
|
|
|
ndm_state |= NUD_NOARP;
|
|
|
|
ndm_state_mask |= NUD_NOARP | NUD_PERMANENT;
|
|
|
|
} else if (strcmp(*argv, "nostatic") == 0) {
|
|
|
|
ndm_state &= ~NUD_NOARP;
|
|
|
|
ndm_state_mask |= NUD_NOARP;
|
2022-06-08 20:29:17 +08:00
|
|
|
} else if (strcmp(*argv, "dynamic") == 0) {
|
|
|
|
ndm_state &= ~NUD_NOARP | NUD_PERMANENT;
|
|
|
|
ndm_state_mask |= NUD_NOARP | NUD_PERMANENT;
|
|
|
|
} else if (strcmp(*argv, "nodynamic") == 0) {
|
|
|
|
ndm_state |= NUD_NOARP;
|
|
|
|
ndm_state_mask |= NUD_NOARP;
|
2022-06-08 20:29:18 +08:00
|
|
|
} else if (strcmp(*argv, "added_by_user") == 0) {
|
|
|
|
ndm_flags |= NTF_USE;
|
|
|
|
ndm_flags_mask |= NTF_USE;
|
|
|
|
} else if (strcmp(*argv, "noadded_by_user") == 0) {
|
|
|
|
ndm_flags &= ~NTF_USE;
|
|
|
|
ndm_flags_mask |= NTF_USE;
|
2022-06-08 20:29:19 +08:00
|
|
|
} else if (strcmp(*argv, "extern_learn") == 0) {
|
|
|
|
ndm_flags |= NTF_EXT_LEARNED;
|
|
|
|
ndm_flags_mask |= NTF_EXT_LEARNED;
|
|
|
|
} else if (strcmp(*argv, "noextern_learn") == 0) {
|
|
|
|
ndm_flags &= ~NTF_EXT_LEARNED;
|
|
|
|
ndm_flags_mask |= NTF_EXT_LEARNED;
|
2022-06-08 20:29:20 +08:00
|
|
|
} else if (strcmp(*argv, "sticky") == 0) {
|
|
|
|
ndm_flags |= NTF_STICKY;
|
|
|
|
ndm_flags_mask |= NTF_STICKY;
|
|
|
|
} else if (strcmp(*argv, "nosticky") == 0) {
|
|
|
|
ndm_flags &= ~NTF_STICKY;
|
|
|
|
ndm_flags_mask |= NTF_STICKY;
|
2022-06-08 20:29:21 +08:00
|
|
|
} else if (strcmp(*argv, "offloaded") == 0) {
|
|
|
|
ndm_flags |= NTF_OFFLOADED;
|
|
|
|
ndm_flags_mask |= NTF_OFFLOADED;
|
|
|
|
} else if (strcmp(*argv, "nooffloaded") == 0) {
|
|
|
|
ndm_flags &= ~NTF_OFFLOADED;
|
|
|
|
ndm_flags_mask |= NTF_OFFLOADED;
|
2023-10-17 18:55:31 +08:00
|
|
|
} else if (strcmp(*argv, "router") == 0) {
|
|
|
|
ndm_flags |= NTF_ROUTER;
|
|
|
|
ndm_flags_mask |= NTF_ROUTER;
|
|
|
|
} else if (strcmp(*argv, "norouter") == 0) {
|
|
|
|
ndm_flags &= ~NTF_ROUTER;
|
|
|
|
ndm_flags_mask |= NTF_ROUTER;
|
2022-06-08 20:29:14 +08:00
|
|
|
} else if (strcmp(*argv, "brport") == 0) {
|
2023-10-17 18:55:25 +08:00
|
|
|
if (brport)
|
2022-06-08 20:29:14 +08:00
|
|
|
duparg2("brport", *argv);
|
|
|
|
NEXT_ARG();
|
2023-10-17 18:55:25 +08:00
|
|
|
brport = *argv;
|
2022-06-08 20:29:13 +08:00
|
|
|
} else if (strcmp(*argv, "vlan") == 0) {
|
|
|
|
if (vid >= 0)
|
|
|
|
duparg2("vlan", *argv);
|
|
|
|
NEXT_ARG();
|
|
|
|
vid = atoi(*argv);
|
2023-10-17 18:55:26 +08:00
|
|
|
} else if (strcmp(*argv, "src_vni") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
src_vni = strtoul(*argv, &endptr, 0);
|
|
|
|
if ((endptr && *endptr) ||
|
|
|
|
(src_vni >> 24) || src_vni == ULONG_MAX)
|
|
|
|
invarg("invalid src VNI\n", *argv);
|
2023-10-17 18:55:27 +08:00
|
|
|
} else if (strcmp(*argv, "nhid") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
if (get_u32(&nhid, *argv, 0))
|
|
|
|
invarg("\"nid\" value is invalid\n", *argv);
|
2023-10-17 18:55:28 +08:00
|
|
|
} 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);
|
2023-10-17 18:55:29 +08:00
|
|
|
} else if (strcmp(*argv, "port") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
port = strtoul(*argv, &endptr, 0);
|
|
|
|
if (endptr && *endptr) {
|
|
|
|
struct servent *pse;
|
|
|
|
|
|
|
|
pse = getservbyname(*argv, "udp");
|
|
|
|
if (!pse)
|
|
|
|
invarg("invalid port\n", *argv);
|
|
|
|
port = ntohs(pse->s_port);
|
|
|
|
} else if (port > 0xffff)
|
|
|
|
invarg("invalid port\n", *argv);
|
2023-10-17 18:55:30 +08:00
|
|
|
} else if (strcmp(*argv, "dst") == 0) {
|
|
|
|
NEXT_ARG();
|
|
|
|
if (dst_ok)
|
|
|
|
duparg2("dst", *argv);
|
|
|
|
get_addr(&dst, *argv, preferred_family);
|
|
|
|
dst_ok = 1;
|
2023-10-10 17:57:50 +08:00
|
|
|
} else if (strcmp(*argv, "help") == 0) {
|
|
|
|
NEXT_ARG();
|
2022-06-08 20:29:12 +08:00
|
|
|
} else {
|
2023-10-10 17:57:50 +08:00
|
|
|
fprintf(stderr, "bridge fdb: unknown command \"%s\"?\n",
|
|
|
|
*argv);
|
|
|
|
usage();
|
|
|
|
return -1;
|
2022-06-08 20:29:12 +08:00
|
|
|
}
|
|
|
|
argc--; argv++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d == NULL) {
|
|
|
|
fprintf(stderr, "Device is a required argument.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
req.ndm.ndm_ifindex = ll_name_to_index(d);
|
|
|
|
if (req.ndm.ndm_ifindex == 0) {
|
|
|
|
fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-10-17 18:55:25 +08:00
|
|
|
if (brport) {
|
|
|
|
brport_ifidx = ll_name_to_index(brport);
|
|
|
|
if (brport_ifidx == 0) {
|
2022-06-08 20:29:14 +08:00
|
|
|
fprintf(stderr, "Cannot find bridge port device \"%s\"\n",
|
2023-10-17 18:55:25 +08:00
|
|
|
brport);
|
2022-06-08 20:29:14 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 20:29:13 +08:00
|
|
|
if (vid >= 4096) {
|
|
|
|
fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-06-08 20:29:12 +08:00
|
|
|
/* if self and master were not specified assume self */
|
|
|
|
if (!(ndm_flags & (NTF_SELF | NTF_MASTER)))
|
|
|
|
ndm_flags |= NTF_SELF;
|
|
|
|
|
|
|
|
req.ndm.ndm_flags = ndm_flags;
|
2022-06-08 20:29:15 +08:00
|
|
|
req.ndm.ndm_state = ndm_state;
|
2023-10-17 18:55:25 +08:00
|
|
|
if (brport_ifidx > -1)
|
|
|
|
addattr32(&req.n, sizeof(req), NDA_IFINDEX, brport_ifidx);
|
2022-06-08 20:29:13 +08:00
|
|
|
if (vid > -1)
|
|
|
|
addattr16(&req.n, sizeof(req), NDA_VLAN, vid);
|
2023-10-17 18:55:26 +08:00
|
|
|
if (src_vni != ~0)
|
|
|
|
addattr32(&req.n, sizeof(req), NDA_SRC_VNI, src_vni);
|
2023-10-17 18:55:27 +08:00
|
|
|
if (nhid > 0)
|
|
|
|
addattr32(&req.n, sizeof(req), NDA_NH_ID, nhid);
|
2023-10-17 18:55:28 +08:00
|
|
|
if (vni != ~0)
|
|
|
|
addattr32(&req.n, sizeof(req), NDA_VNI, vni);
|
2023-10-17 18:55:29 +08:00
|
|
|
if (port) {
|
|
|
|
unsigned short dport;
|
|
|
|
|
|
|
|
dport = htons((unsigned short)port);
|
|
|
|
addattr16(&req.n, sizeof(req), NDA_PORT, dport);
|
|
|
|
}
|
2023-10-17 18:55:30 +08:00
|
|
|
if (dst_ok)
|
|
|
|
addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen);
|
2022-06-08 20:29:18 +08:00
|
|
|
if (ndm_flags_mask)
|
|
|
|
addattr8(&req.n, sizeof(req), NDA_NDM_FLAGS_MASK,
|
|
|
|
ndm_flags_mask);
|
2022-06-08 20:29:15 +08:00
|
|
|
if (ndm_state_mask)
|
|
|
|
addattr16(&req.n, sizeof(req), NDA_NDM_STATE_MASK,
|
|
|
|
ndm_state_mask);
|
2022-06-08 20:29:12 +08:00
|
|
|
|
|
|
|
if (rtnl_talk(&rth, &req.n, NULL) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-02 06:23:49 +08:00
|
|
|
int do_fdb(int argc, char **argv)
|
|
|
|
{
|
|
|
|
ll_init_map(&rth);
|
2022-09-22 14:19:35 +08:00
|
|
|
timestamp = 0;
|
2012-08-02 06:23:49 +08:00
|
|
|
|
|
|
|
if (argc > 0) {
|
|
|
|
if (matches(*argv, "add") == 0)
|
|
|
|
return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
|
2013-05-01 11:21:22 +08:00
|
|
|
if (matches(*argv, "append") == 0)
|
|
|
|
return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_APPEND, argc-1, argv+1);
|
2013-07-30 14:16:41 +08:00
|
|
|
if (matches(*argv, "replace") == 0)
|
|
|
|
return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
|
2012-08-02 06:23:49 +08:00
|
|
|
if (matches(*argv, "delete") == 0)
|
|
|
|
return fdb_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
|
2019-10-01 12:52:22 +08:00
|
|
|
if (matches(*argv, "get") == 0)
|
|
|
|
return fdb_get(argc-1, argv+1);
|
2012-08-02 06:23:49 +08:00
|
|
|
if (matches(*argv, "show") == 0 ||
|
|
|
|
matches(*argv, "lst") == 0 ||
|
|
|
|
matches(*argv, "list") == 0)
|
|
|
|
return fdb_show(argc-1, argv+1);
|
2022-06-08 20:29:12 +08:00
|
|
|
if (strcmp(*argv, "flush") == 0)
|
|
|
|
return fdb_flush(argc-1, argv+1);
|
2012-08-02 06:23:49 +08:00
|
|
|
if (matches(*argv, "help") == 0)
|
|
|
|
usage();
|
|
|
|
} else
|
|
|
|
return fdb_show(0, NULL);
|
|
|
|
|
2012-08-20 14:28:47 +08:00
|
|
|
fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv);
|
2012-08-02 06:23:49 +08:00
|
|
|
exit(-1);
|
|
|
|
}
|