nexthop: Add support for nexthop buckets
Add ability to dump multiple nexthop buckets and get a specific one.
Example:
# ip nexthop add id 10 group 1/2 type resilient buckets 8
# ip nexthop
id 1 via 192.0.2.2 dev dummy10 scope link
id 2 via 192.0.2.19 dev dummy20 scope link
id 10 group 1/2 type resilient buckets 8 idle_timer 120 unbalanced_timer 0 unbalanced_time 0
# ip nexthop bucket
id 10 index 0 idle_time 28.1 nhid 2
id 10 index 1 idle_time 28.1 nhid 2
id 10 index 2 idle_time 28.1 nhid 2
id 10 index 3 idle_time 28.1 nhid 2
id 10 index 4 idle_time 28.1 nhid 1
id 10 index 5 idle_time 28.1 nhid 1
id 10 index 6 idle_time 28.1 nhid 1
id 10 index 7 idle_time 28.1 nhid 1
# ip nexthop bucket show nhid 1
id 10 index 4 idle_time 53.59 nhid 1
id 10 index 5 idle_time 53.59 nhid 1
id 10 index 6 idle_time 53.59 nhid 1
id 10 index 7 idle_time 53.59 nhid 1
# ip nexthop bucket get id 10 index 5
id 10 index 5 idle_time 81 nhid 1
# ip -j -p nexthop bucket get id 10 index 5
[ {
"id": 10,
"bucket": {
"index": 5,
"idle_time": 104.89,
"nhid": 1
},
"flags": [ ]
} ]
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
parent
9167671822
commit
2be6d18b30
|
|
@ -97,6 +97,9 @@ int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
|
||||||
int rtnl_nexthopdump_req(struct rtnl_handle *rth, int family,
|
int rtnl_nexthopdump_req(struct rtnl_handle *rth, int family,
|
||||||
req_filter_fn_t filter_fn)
|
req_filter_fn_t filter_fn)
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
|
int rtnl_nexthop_bucket_dump_req(struct rtnl_handle *rth, int family,
|
||||||
|
req_filter_fn_t filter_fn)
|
||||||
|
__attribute__((warn_unused_result));
|
||||||
|
|
||||||
struct rtnl_ctrl_data {
|
struct rtnl_ctrl_data {
|
||||||
int nsid;
|
int nsid;
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ int print_rule(struct nlmsghdr *n, void *arg);
|
||||||
int print_netconf(struct rtnl_ctrl_data *ctrl,
|
int print_netconf(struct rtnl_ctrl_data *ctrl,
|
||||||
struct nlmsghdr *n, void *arg);
|
struct nlmsghdr *n, void *arg);
|
||||||
int print_nexthop(struct nlmsghdr *n, void *arg);
|
int print_nexthop(struct nlmsghdr *n, void *arg);
|
||||||
|
int print_nexthop_bucket(struct nlmsghdr *n, void *arg);
|
||||||
void netns_map_init(void);
|
void netns_map_init(void);
|
||||||
void netns_nsid_socket_init(void);
|
void netns_nsid_socket_init(void);
|
||||||
int print_nsid(struct nlmsghdr *n, void *arg);
|
int print_nsid(struct nlmsghdr *n, void *arg);
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,12 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl,
|
||||||
print_nexthop(n, arg);
|
print_nexthop(n, arg);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case RTM_NEWNEXTHOPBUCKET:
|
||||||
|
case RTM_DELNEXTHOPBUCKET:
|
||||||
|
print_headers(fp, "[NEXTHOPBUCKET]", ctrl);
|
||||||
|
print_nexthop_bucket(n, arg);
|
||||||
|
return 0;
|
||||||
|
|
||||||
case RTM_NEWLINK:
|
case RTM_NEWLINK:
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
ll_remember_index(n, NULL);
|
ll_remember_index(n, NULL);
|
||||||
|
|
|
||||||
254
ip/ipnexthop.c
254
ip/ipnexthop.c
|
|
@ -21,6 +21,8 @@ static struct {
|
||||||
unsigned int master;
|
unsigned int master;
|
||||||
unsigned int proto;
|
unsigned int proto;
|
||||||
unsigned int fdb;
|
unsigned int fdb;
|
||||||
|
unsigned int id;
|
||||||
|
unsigned int nhid;
|
||||||
} filter;
|
} filter;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -39,8 +41,11 @@ static void usage(void)
|
||||||
"Usage: ip nexthop { list | flush } [ protocol ID ] SELECTOR\n"
|
"Usage: ip nexthop { list | flush } [ protocol ID ] SELECTOR\n"
|
||||||
" ip nexthop { add | replace } id ID NH [ protocol ID ]\n"
|
" ip nexthop { add | replace } id ID NH [ protocol ID ]\n"
|
||||||
" ip nexthop { get | del } id ID\n"
|
" ip nexthop { get | del } id ID\n"
|
||||||
|
" ip nexthop bucket list BUCKET_SELECTOR\n"
|
||||||
|
" ip nexthop bucket get id ID index INDEX\n"
|
||||||
"SELECTOR := [ id ID ] [ dev DEV ] [ vrf NAME ] [ master DEV ]\n"
|
"SELECTOR := [ id ID ] [ dev DEV ] [ vrf NAME ] [ master DEV ]\n"
|
||||||
" [ groups ] [ fdb ]\n"
|
" [ groups ] [ fdb ]\n"
|
||||||
|
"BUCKET_SELECTOR := SELECTOR | [ nhid ID ]\n"
|
||||||
"NH := { blackhole | [ via ADDRESS ] [ dev DEV ] [ onlink ]\n"
|
"NH := { blackhole | [ via ADDRESS ] [ dev DEV ] [ onlink ]\n"
|
||||||
" [ encap ENCAPTYPE ENCAPHDR ] |\n"
|
" [ encap ENCAPTYPE ENCAPHDR ] |\n"
|
||||||
" group GROUP [ fdb ] [ type TYPE [ TYPE_ARGS ] ] }\n"
|
" group GROUP [ fdb ] [ type TYPE [ TYPE_ARGS ] ] }\n"
|
||||||
|
|
@ -85,6 +90,36 @@ static int nh_dump_filter(struct nlmsghdr *nlh, int reqlen)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nh_dump_bucket_filter(struct nlmsghdr *nlh, int reqlen)
|
||||||
|
{
|
||||||
|
struct rtattr *nest;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
err = nh_dump_filter(nlh, reqlen);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (filter.id) {
|
||||||
|
err = addattr32(nlh, reqlen, NHA_ID, filter.id);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.nhid) {
|
||||||
|
nest = addattr_nest(nlh, reqlen, NHA_RES_BUCKET);
|
||||||
|
nest->rta_type |= NLA_F_NESTED;
|
||||||
|
|
||||||
|
err = addattr32(nlh, reqlen, NHA_RES_BUCKET_NH_ID,
|
||||||
|
filter.nhid);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
addattr_nest_end(nlh, nest);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static struct rtnl_handle rth_del = { .fd = -1 };
|
static struct rtnl_handle rth_del = { .fd = -1 };
|
||||||
|
|
||||||
static int delete_nexthop(__u32 id)
|
static int delete_nexthop(__u32 id)
|
||||||
|
|
@ -266,6 +301,33 @@ static void print_nh_res_group(FILE *fp, const struct rtattr *res_grp_attr)
|
||||||
close_json_object();
|
close_json_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_nh_res_bucket(FILE *fp, const struct rtattr *res_bucket_attr)
|
||||||
|
{
|
||||||
|
struct rtattr *tb[NHA_RES_BUCKET_MAX + 1];
|
||||||
|
|
||||||
|
parse_rtattr_nested(tb, NHA_RES_BUCKET_MAX, res_bucket_attr);
|
||||||
|
|
||||||
|
open_json_object("bucket");
|
||||||
|
|
||||||
|
if (tb[NHA_RES_BUCKET_INDEX])
|
||||||
|
print_uint(PRINT_ANY, "index", "index %u ",
|
||||||
|
rta_getattr_u16(tb[NHA_RES_BUCKET_INDEX]));
|
||||||
|
|
||||||
|
if (tb[NHA_RES_BUCKET_IDLE_TIME]) {
|
||||||
|
struct rtattr *rta = tb[NHA_RES_BUCKET_IDLE_TIME];
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
__jiffies_to_tv(&tv, rta_getattr_u64(rta));
|
||||||
|
print_tv(PRINT_ANY, "idle_time", "idle_time %g ", &tv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tb[NHA_RES_BUCKET_NH_ID])
|
||||||
|
print_uint(PRINT_ANY, "nhid", "nhid %u ",
|
||||||
|
rta_getattr_u32(tb[NHA_RES_BUCKET_NH_ID]));
|
||||||
|
|
||||||
|
close_json_object();
|
||||||
|
}
|
||||||
|
|
||||||
int print_nexthop(struct nlmsghdr *n, void *arg)
|
int print_nexthop(struct nlmsghdr *n, void *arg)
|
||||||
{
|
{
|
||||||
struct nhmsg *nhm = NLMSG_DATA(n);
|
struct nhmsg *nhm = NLMSG_DATA(n);
|
||||||
|
|
@ -346,6 +408,50 @@ int print_nexthop(struct nlmsghdr *n, void *arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int print_nexthop_bucket(struct nlmsghdr *n, void *arg)
|
||||||
|
{
|
||||||
|
struct nhmsg *nhm = NLMSG_DATA(n);
|
||||||
|
struct rtattr *tb[NHA_MAX+1];
|
||||||
|
FILE *fp = (FILE *)arg;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (n->nlmsg_type != RTM_DELNEXTHOPBUCKET &&
|
||||||
|
n->nlmsg_type != RTM_NEWNEXTHOPBUCKET) {
|
||||||
|
fprintf(stderr, "Not a nexthop bucket: %08x %08x %08x\n",
|
||||||
|
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = n->nlmsg_len - NLMSG_SPACE(sizeof(*nhm));
|
||||||
|
if (len < 0) {
|
||||||
|
close_json_object();
|
||||||
|
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_rtattr_flags(tb, NHA_MAX, RTM_NHA(nhm), len, NLA_F_NESTED);
|
||||||
|
|
||||||
|
open_json_object(NULL);
|
||||||
|
|
||||||
|
if (n->nlmsg_type == RTM_DELNEXTHOP)
|
||||||
|
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
|
||||||
|
|
||||||
|
if (tb[NHA_ID])
|
||||||
|
print_uint(PRINT_ANY, "id", "id %u ",
|
||||||
|
rta_getattr_u32(tb[NHA_ID]));
|
||||||
|
|
||||||
|
if (tb[NHA_RES_BUCKET])
|
||||||
|
print_nh_res_bucket(fp, tb[NHA_RES_BUCKET]);
|
||||||
|
|
||||||
|
print_rt_flags(fp, nhm->nh_flags);
|
||||||
|
|
||||||
|
print_string(PRINT_FP, NULL, "%s", "\n");
|
||||||
|
close_json_object();
|
||||||
|
fflush(fp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int add_nh_group_attr(struct nlmsghdr *n, int maxlen, char *argv)
|
static int add_nh_group_attr(struct nlmsghdr *n, int maxlen, char *argv)
|
||||||
{
|
{
|
||||||
struct nexthop_grp *grps;
|
struct nexthop_grp *grps;
|
||||||
|
|
@ -721,6 +827,151 @@ static int ipnh_get(int argc, char **argv)
|
||||||
return ipnh_get_id(id);
|
return ipnh_get_id(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ipnh_bucket_list(int argc, char **argv)
|
||||||
|
{
|
||||||
|
while (argc > 0) {
|
||||||
|
if (!matches(*argv, "dev")) {
|
||||||
|
NEXT_ARG();
|
||||||
|
filter.ifindex = ll_name_to_index(*argv);
|
||||||
|
if (!filter.ifindex)
|
||||||
|
invarg("Device does not exist\n", *argv);
|
||||||
|
} else if (!matches(*argv, "master")) {
|
||||||
|
NEXT_ARG();
|
||||||
|
filter.master = ll_name_to_index(*argv);
|
||||||
|
if (!filter.master)
|
||||||
|
invarg("Device does not exist\n", *argv);
|
||||||
|
} else if (matches(*argv, "vrf") == 0) {
|
||||||
|
NEXT_ARG();
|
||||||
|
if (!name_is_vrf(*argv))
|
||||||
|
invarg("Invalid VRF\n", *argv);
|
||||||
|
filter.master = ll_name_to_index(*argv);
|
||||||
|
if (!filter.master)
|
||||||
|
invarg("VRF does not exist\n", *argv);
|
||||||
|
} else if (!strcmp(*argv, "id")) {
|
||||||
|
NEXT_ARG();
|
||||||
|
filter.id = ipnh_parse_id(*argv);
|
||||||
|
} else if (!strcmp(*argv, "nhid")) {
|
||||||
|
NEXT_ARG();
|
||||||
|
filter.nhid = ipnh_parse_id(*argv);
|
||||||
|
} else if (matches(*argv, "help") == 0) {
|
||||||
|
usage();
|
||||||
|
} else {
|
||||||
|
invarg("", *argv);
|
||||||
|
}
|
||||||
|
argc--; argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtnl_nexthop_bucket_dump_req(&rth, preferred_family,
|
||||||
|
nh_dump_bucket_filter) < 0) {
|
||||||
|
perror("Cannot send dump request");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_json_obj(json);
|
||||||
|
|
||||||
|
if (rtnl_dump_filter(&rth, print_nexthop_bucket, stdout) < 0) {
|
||||||
|
fprintf(stderr, "Dump terminated\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_json_obj();
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ipnh_bucket_get_id(__u32 id, __u16 bucket_index)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
struct nlmsghdr n;
|
||||||
|
struct nhmsg nhm;
|
||||||
|
char buf[1024];
|
||||||
|
} req = {
|
||||||
|
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)),
|
||||||
|
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||||
|
.n.nlmsg_type = RTM_GETNEXTHOPBUCKET,
|
||||||
|
.nhm.nh_family = preferred_family,
|
||||||
|
};
|
||||||
|
struct nlmsghdr *answer;
|
||||||
|
struct rtattr *nest;
|
||||||
|
|
||||||
|
addattr32(&req.n, sizeof(req), NHA_ID, id);
|
||||||
|
|
||||||
|
nest = addattr_nest(&req.n, sizeof(req), NHA_RES_BUCKET);
|
||||||
|
nest->rta_type |= NLA_F_NESTED;
|
||||||
|
|
||||||
|
addattr16(&req.n, sizeof(req), NHA_RES_BUCKET_INDEX, bucket_index);
|
||||||
|
|
||||||
|
addattr_nest_end(&req.n, nest);
|
||||||
|
|
||||||
|
if (rtnl_talk(&rth, &req.n, &answer) < 0)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
new_json_obj(json);
|
||||||
|
|
||||||
|
if (print_nexthop_bucket(answer, (void *)stdout) < 0) {
|
||||||
|
free(answer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete_json_obj();
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
free(answer);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ipnh_bucket_get(int argc, char **argv)
|
||||||
|
{
|
||||||
|
bool bucket_valid = false;
|
||||||
|
__u16 bucket_index;
|
||||||
|
__u32 id = 0;
|
||||||
|
|
||||||
|
while (argc > 0) {
|
||||||
|
if (!strcmp(*argv, "id")) {
|
||||||
|
NEXT_ARG();
|
||||||
|
id = ipnh_parse_id(*argv);
|
||||||
|
} else if (!strcmp(*argv, "index")) {
|
||||||
|
NEXT_ARG();
|
||||||
|
if (get_u16(&bucket_index, *argv, 0))
|
||||||
|
invarg("invalid bucket index value", *argv);
|
||||||
|
bucket_valid = true;
|
||||||
|
} else {
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
argc--; argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id || !bucket_valid) {
|
||||||
|
usage();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipnh_bucket_get_id(id, bucket_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_ipnh_bucket(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc < 1)
|
||||||
|
return ipnh_bucket_list(0, NULL);
|
||||||
|
|
||||||
|
if (!matches(*argv, "list") ||
|
||||||
|
!matches(*argv, "show") ||
|
||||||
|
!matches(*argv, "lst"))
|
||||||
|
return ipnh_bucket_list(argc-1, argv+1);
|
||||||
|
|
||||||
|
if (!matches(*argv, "get"))
|
||||||
|
return ipnh_bucket_get(argc-1, argv+1);
|
||||||
|
|
||||||
|
if (!matches(*argv, "help"))
|
||||||
|
usage();
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"Command \"%s\" is unknown, try \"ip nexthop help\".\n", *argv);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
int do_ipnh(int argc, char **argv)
|
int do_ipnh(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc < 1)
|
if (argc < 1)
|
||||||
|
|
@ -746,6 +997,9 @@ int do_ipnh(int argc, char **argv)
|
||||||
if (!matches(*argv, "flush"))
|
if (!matches(*argv, "flush"))
|
||||||
return ipnh_list_flush(argc-1, argv+1, IPNH_FLUSH);
|
return ipnh_list_flush(argc-1, argv+1, IPNH_FLUSH);
|
||||||
|
|
||||||
|
if (!matches(*argv, "bucket"))
|
||||||
|
return do_ipnh_bucket(argc-1, argv+1);
|
||||||
|
|
||||||
if (!matches(*argv, "help"))
|
if (!matches(*argv, "help"))
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -282,6 +282,32 @@ int rtnl_nexthopdump_req(struct rtnl_handle *rth, int family,
|
||||||
return send(rth->fd, &req, sizeof(req), 0);
|
return send(rth->fd, &req, sizeof(req), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rtnl_nexthop_bucket_dump_req(struct rtnl_handle *rth, int family,
|
||||||
|
req_filter_fn_t filter_fn)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
struct nlmsghdr nlh;
|
||||||
|
struct nhmsg nhm;
|
||||||
|
char buf[128];
|
||||||
|
} req = {
|
||||||
|
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)),
|
||||||
|
.nlh.nlmsg_type = RTM_GETNEXTHOPBUCKET,
|
||||||
|
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||||
|
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||||
|
.nhm.nh_family = family,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (filter_fn) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = filter_fn(&req.nlh, sizeof(req));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return send(rth->fd, &req, sizeof(req), 0);
|
||||||
|
}
|
||||||
|
|
||||||
int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
|
int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
|
||||||
req_filter_fn_t filter_fn)
|
req_filter_fn_t filter_fn)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,14 @@ ip-nexthop \- nexthop object management
|
||||||
.BR "ip nexthop" " { " get " | " del " } id "
|
.BR "ip nexthop" " { " get " | " del " } id "
|
||||||
.I ID
|
.I ID
|
||||||
|
|
||||||
|
.ti -8
|
||||||
|
.BI "ip nexthop bucket list " BUCKET_SELECTOR
|
||||||
|
|
||||||
|
.ti -8
|
||||||
|
.BR "ip nexthop bucket get " id
|
||||||
|
.I ID
|
||||||
|
.RI "index " INDEX
|
||||||
|
|
||||||
.ti -8
|
.ti -8
|
||||||
.IR SELECTOR " := "
|
.IR SELECTOR " := "
|
||||||
.RB "[ " id
|
.RB "[ " id
|
||||||
|
|
@ -41,6 +49,12 @@ ip-nexthop \- nexthop object management
|
||||||
.BR groups " ] [ "
|
.BR groups " ] [ "
|
||||||
.BR fdb " ]"
|
.BR fdb " ]"
|
||||||
|
|
||||||
|
.ti -8
|
||||||
|
.IR BUCKET_SELECTOR " := "
|
||||||
|
.IR SELECTOR
|
||||||
|
.RB " | [ " nhid
|
||||||
|
.IR ID " ]"
|
||||||
|
|
||||||
.ti -8
|
.ti -8
|
||||||
.IR NH " := { "
|
.IR NH " := { "
|
||||||
.BR blackhole " | [ "
|
.BR blackhole " | [ "
|
||||||
|
|
@ -230,6 +244,37 @@ as show.
|
||||||
ip nexthop get id ID
|
ip nexthop get id ID
|
||||||
get a single nexthop by id
|
get a single nexthop by id
|
||||||
|
|
||||||
|
.TP
|
||||||
|
ip nexthop bucket show
|
||||||
|
show the contents of the nexthop bucket table or the nexthop buckets
|
||||||
|
selected by some criteria.
|
||||||
|
.RS
|
||||||
|
.TP
|
||||||
|
.BI id " ID "
|
||||||
|
.in +0
|
||||||
|
show the nexthop buckets that belong to a nexthop group with a given id
|
||||||
|
.TP
|
||||||
|
.BI nhid " ID "
|
||||||
|
.in +0
|
||||||
|
show the nexthop buckets that hold a nexthop with a given id
|
||||||
|
.TP
|
||||||
|
.BI dev " DEV "
|
||||||
|
.in +0
|
||||||
|
show the nexthop buckets using the given device
|
||||||
|
.TP
|
||||||
|
.BI vrf " NAME "
|
||||||
|
.in +0
|
||||||
|
show the nexthop buckets using devices associated with the vrf name
|
||||||
|
.TP
|
||||||
|
.BI master " DEV "
|
||||||
|
.in +0
|
||||||
|
show the nexthop buckets using devices enslaved to given master device
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.TP
|
||||||
|
ip nexthop bucket get id ID index INDEX
|
||||||
|
get a single nexthop bucket by nexthop group id and bucket index
|
||||||
|
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
.PP
|
.PP
|
||||||
ip nexthop ls
|
ip nexthop ls
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue