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"
|
|
|
|
|
2017-01-13 00:47:39 +08:00
|
|
|
static unsigned int filter_index, filter_vlan, filter_state;
|
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"
|
2018-09-27 21:35:12 +08:00
|
|
|
" [ sticky ] [ local | static | dynamic ] [ dst IPADDR ]\n"
|
|
|
|
" [ vlan VID ] [ port PORT] [ vni VNI ] [ via DEV ]\n"
|
2017-10-27 15:15:23 +08:00
|
|
|
" bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] [ state STATE ] ]\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 "";
|
|
|
|
|
|
|
|
sprintf(buf, "state=%#x", s);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
static void fdb_print_flags(FILE *fp, unsigned int flags)
|
|
|
|
{
|
|
|
|
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");
|
|
|
|
|
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];
|
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)));
|
|
|
|
|
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;
|
|
|
|
|
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
|
|
|
|
2018-11-08 07:14:09 +08:00
|
|
|
if (!filter_index && r->ndm_ifindex)
|
2018-02-21 03:24:05 +08:00
|
|
|
print_color_string(PRINT_ANY, COLOR_IFNAME,
|
2018-10-09 20:44:08 +08:00
|
|
|
"ifname", "dev %s ",
|
2018-02-21 03:24:05 +08:00
|
|
|
ll_index_to_name(r->ndm_ifindex));
|
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
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
print_color_string(PRINT_ANY,
|
|
|
|
ifa_family_color(family),
|
2018-10-09 20:44:08 +08:00
|
|
|
"dst", "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
|
|
|
|
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
|
|
|
|
2018-02-21 03:24:05 +08:00
|
|
|
fdb_print_flags(fp, r->ndm_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fdb_show(int argc, char **argv)
|
|
|
|
{
|
2014-07-04 20:37:10 +08:00
|
|
|
struct {
|
2016-03-22 02:56:01 +08:00
|
|
|
struct nlmsghdr n;
|
2018-12-31 01:14:54 +08:00
|
|
|
struct ndmsg ndm;
|
2016-03-22 02:56:01 +08:00
|
|
|
char buf[256];
|
2016-07-18 22:48:42 +08:00
|
|
|
} req = {
|
2018-12-31 01:14:54 +08:00
|
|
|
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
|
|
|
|
.ndm.ndm_family = PF_BRIDGE,
|
2016-07-18 22:48:42 +08:00
|
|
|
};
|
2014-07-04 20:37:10 +08:00
|
|
|
|
2012-08-02 06:23:49 +08:00
|
|
|
char *filter_dev = NULL;
|
2014-07-04 20:37:10 +08:00
|
|
|
char *br = NULL;
|
2018-12-31 01:14:54 +08:00
|
|
|
int msg_size = sizeof(struct ndmsg);
|
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;
|
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;
|
|
|
|
}
|
|
|
|
addattr32(&req.n, sizeof(req), IFLA_MASTER, br_ifindex);
|
|
|
|
msg_size += RTA_LENGTH(4);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*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);
|
2018-12-31 01:14:54 +08:00
|
|
|
req.ndm.ndm_ifindex = filter_index;
|
2012-08-02 06:23:49 +08:00
|
|
|
}
|
|
|
|
|
2018-12-31 01:14:54 +08:00
|
|
|
if (rtnl_dump_request(&rth, RTM_GETNEIGH, &req.ndm, msg_size) < 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;
|
|
|
|
unsigned int via = 0;
|
|
|
|
char *endptr;
|
2013-02-28 18:04:04 +08:00
|
|
|
short vid = -1;
|
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;
|
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);
|
|
|
|
} 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
|
|
|
}
|
|
|
|
|
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);
|
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);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
int do_fdb(int argc, char **argv)
|
|
|
|
{
|
|
|
|
ll_init_map(&rth);
|
|
|
|
|
|
|
|
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);
|
|
|
|
if (matches(*argv, "show") == 0 ||
|
|
|
|
matches(*argv, "lst") == 0 ||
|
|
|
|
matches(*argv, "list") == 0)
|
|
|
|
return fdb_show(argc-1, argv+1);
|
|
|
|
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);
|
|
|
|
}
|