This implements a way to add a limit for bgpctl show rib output.
When a limit is set then the output will include a token (at the end)
that can be used to get the next batch of output. These two things allow
to build a frontend that puts the output onto multiple pages.
Both regular output and JSON output include the token.
A simple but dumb example of this:
set -e
TMP=$(mktemp)
while true; do
bgpctl show rib limit 100 $token | tee "$TMP"
token=$(grep ^token "$TMP")
done
This can be used for looking glass software to limit output and offer
people a way to page through the output.
--
:wq Claudio
Index: bgpctl/bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.263
diff -u -p -r1.263 bgpctl.c
--- bgpctl/bgpctl.c 10 May 2020 13:38:46 -0000 1.263
+++ bgpctl/bgpctl.c 13 May 2020 14:41:24 -0000
@@ -240,6 +240,8 @@ main(int argc, char *argv[])
strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
ribreq.aid = res->aid;
ribreq.flags = res->flags;
+ ribreq.limit = res->limit;
+ ribreq.token = res->token;
imsg_compose(ibuf, type, 0, 0, -1, &ribreq, sizeof(ribreq));
break;
case SHOW_RIB_MEM:
@@ -391,11 +393,12 @@ show(struct imsg *imsg, struct parse_res
{
struct peer *p;
struct ctl_timer *t;
- struct ctl_show_interface *iface;
struct ctl_show_nexthop *nh;
struct kroute_full *kf;
struct ktable *kt;
struct ctl_show_rib rib;
+ struct ctl_show_rib_token token;
+ struct ctl_show_interface *iface;
u_char *asdata;
struct rde_memstats stats;
struct rde_hashstats hash;
@@ -466,6 +469,14 @@ show(struct imsg *imsg, struct parse_res
memcpy(&hash, imsg->data, sizeof(hash));
output->rib_hash(&hash);
break;
+ case IMSG_CTL_TOKEN:
+ if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(token)) {
+ warnx("got IMSG_CTL_TOKEN with wrong len");
+ break;
+ }
+ memcpy(&token, imsg->data, sizeof(token));
+ output->token(&token);
+ break;
case IMSG_CTL_RESULT:
if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(rescode)) {
warnx("got IMSG_CTL_RESULT with wrong len");
@@ -975,6 +986,20 @@ fmt_ext_community(u_int8_t *data)
(unsigned long long)be64toh(ext));
return buf;
}
+}
+
+const char *
+fmt_token(struct ctl_show_rib_token *t)
+{
+ static char buf[128];
+
+ snprintf(buf, sizeof(buf), "%d:%d:%u:%x:%x:%x:%x:%x:%x:%x:%x:%d",
+ t->peerid, t->prefix.aid, t->prefix.scope_id,
+ t->prefix.addr32[0], t->prefix.addr32[1], t->prefix.addr32[2],
+ t->prefix.addr32[3], t->prefix.addr32[4], t->prefix.addr32[5],
+ t->prefix.addr32[6], t->prefix.addr32[7], t->prefixlen);
+
+ return buf;
}
void
Index: bgpctl/bgpctl.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.h,v
retrieving revision 1.7
diff -u -p -r1.7 bgpctl.h
--- bgpctl/bgpctl.h 2 May 2020 14:33:33 -0000 1.7
+++ bgpctl/bgpctl.h 13 May 2020 10:00:49 -0000
@@ -30,6 +30,7 @@ struct output {
struct parse_result *);
void (*rib_hash)(struct rde_hashstats *);
void (*rib_mem)(struct rde_memstats *);
+ void (*token)(struct ctl_show_rib_token *);
void (*result)(u_int);
void (*tail)(void);
};
@@ -53,3 +54,4 @@ const char *fmt_attr(u_int8_t, int);
const char *fmt_community(u_int16_t, u_int16_t);
const char *fmt_large_community(u_int32_t, u_int32_t, u_int32_t);
const char *fmt_ext_community(u_int8_t *);
+const char *fmt_token(struct ctl_show_rib_token *);
Index: bgpctl/json.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/json.c,v
retrieving revision 1.2
diff -u -p -r1.2 json.c
--- bgpctl/json.c 4 May 2020 16:00:13 -0000 1.2
+++ bgpctl/json.c 14 May 2020 14:57:32 -0000
@@ -117,6 +117,20 @@ json_do_array(const char *name)
}
void
+json_do_end_array(const char *name)
+{
+ int l;
+
+ l = do_find(ARRAY, name);
+ if (l == -1)
+ errx(1, "json array %s not found", name);
+
+ /* array already in use, close element and move on */
+ while (level >= l)
+ json_do_end();
+}
+
+void
json_do_object(const char *name)
{
int i, l;
Index: bgpctl/json.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/json.h,v
retrieving revision 1.2
diff -u -p -r1.2 json.h
--- bgpctl/json.h 4 May 2020 16:00:13 -0000 1.2
+++ bgpctl/json.h 14 May 2020 14:54:04 -0000
@@ -20,6 +20,7 @@
void json_do_start(void);
void json_do_finish(void);
void json_do_array(const char *);
+void json_do_end_array(const char *);
void json_do_object(const char *);
void json_do_end(void);
void json_do_printf(const char *, const char *, ...)
Index: bgpctl/output.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v
retrieving revision 1.9
diff -u -p -r1.9 output.c
--- bgpctl/output.c 10 May 2020 13:38:46 -0000 1.9
+++ bgpctl/output.c 13 May 2020 14:45:18 -0000
@@ -957,6 +957,12 @@ show_rib_hash(struct rde_hashstats *hash
}
static void
+show_token(struct ctl_show_rib_token *t)
+{
+ printf("token %s\n", fmt_token(t));
+}
+
+static void
show_result(u_int rescode)
{
if (rescode == 0)
@@ -987,6 +993,7 @@ const struct output show_output = {
.rib = show_rib,
.rib_mem = show_rib_mem,
.rib_hash = show_rib_hash,
+ .token = show_token,
.result = show_result,
.tail = show_tail
};
Index: bgpctl/output_json.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output_json.c,v
retrieving revision 1.3
diff -u -p -r1.3 output_json.c
--- bgpctl/output_json.c 10 May 2020 13:38:46 -0000 1.3
+++ bgpctl/output_json.c 14 May 2020 15:05:00 -0000
@@ -58,7 +58,7 @@ json_neighbor_capabilities(struct capabi
for (i = 0; i < AID_MAX; i++)
if (capa->mp[i])
json_do_printf("mp", "%s", aid2str(i));
- json_do_end();
+ json_do_end_array("multiprotocol");
}
if (capa->grestart.restart) {
int restarted = 0, present = 0;
@@ -70,6 +70,7 @@ json_neighbor_capabilities(struct capabi
restarted = 1;
break;
}
+
json_do_object("graceful_restart");
json_do_bool("eor", 1);
json_do_bool("restart", restarted);
@@ -89,7 +90,7 @@ json_neighbor_capabilities(struct capabi
CAPA_GR_FORWARD);
json_do_end();
}
- json_do_end();
+ json_do_end_array("protocols");
}
json_do_end();
@@ -487,7 +488,7 @@ json_do_community(u_char *data, uint16_t
json_do_printf("community", "%s", fmt_community(a, v));
}
- json_do_end();
+ json_do_end_array("communities");
}
static void
@@ -515,7 +516,7 @@ json_do_large_community(u_char *data, ui
fmt_large_community(a, l1, l2));
}
- json_do_end();
+ json_do_end_array("large_communities");
}
static void
@@ -533,7 +534,7 @@ json_do_ext_community(u_char *data, uint
for (i = 0; i < len; i += 8)
json_do_printf("community", "%s", fmt_ext_community(data + i));
- json_do_end();
+ json_do_end_array("extended_communities");
}
static void
@@ -762,6 +763,7 @@ bad_len:
data += pos;
alen -= pos;
}
+ json_do_end_array("NLRI");
break;
case ATTR_EXT_COMMUNITIES:
json_do_ext_community(data, alen);
@@ -918,6 +920,13 @@ json_rib_hash(struct rde_hashstats *hash
}
static void
+json_token(struct ctl_show_rib_token *t)
+{
+ json_do_end_array("rib");
+ json_do_printf("token", "%s", fmt_token(t));
+}
+
+static void
json_result(u_int rescode)
{
if (rescode == 0)
@@ -951,6 +960,7 @@ const struct output json_output = {
.rib = json_rib,
.rib_mem = json_rib_mem,
.rib_hash = json_rib_hash,
+ .token = json_token,
.result = json_result,
.tail = json_tail
};
Index: bgpctl/parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v
retrieving revision 1.104
diff -u -p -r1.104 parser.c
--- bgpctl/parser.c 12 May 2020 13:26:02 -0000 1.104
+++ bgpctl/parser.c 14 May 2020 11:03:57 -0000
@@ -61,7 +61,9 @@ enum token_type {
RD,
FAMILY,
RTABLE,
- FILENAME
+ FILENAME,
+ TOKEN,
+ LIMIT
};
struct token {
@@ -110,6 +112,8 @@ static const struct token t_pftable[];
static const struct token t_prepnbr[];
static const struct token t_prepself[];
static const struct token t_weight[];
+static const struct token t_limit[];
+static const struct token t_token[];
static const struct token t_log[];
static const struct token t_fib_table[];
static const struct token t_show_fib_table[];
@@ -168,6 +172,7 @@ static const struct token t_show_rib[] =
{ KEYWORD, "community", NONE, t_show_community},
{ KEYWORD, "ext-community", NONE, t_show_extcommunity},
{ KEYWORD, "large-community", NONE, t_show_largecommunity},
+ { KEYWORD, "ovs", NONE, t_show_ovs},
{ FLAG, "best", F_CTL_ACTIVE, t_show_rib},
{ FLAG, "selected", F_CTL_ACTIVE, t_show_rib},
{ FLAG, "detail", F_CTL_DETAIL, t_show_rib},
@@ -179,7 +184,8 @@ static const struct token t_show_rib[] =
{ KEYWORD, "table", NONE, t_show_rib_rib},
{ KEYWORD, "summary", SHOW_SUMMARY, t_show_summary},
{ KEYWORD, "memory", SHOW_RIB_MEM, NULL},
- { KEYWORD, "ovs", NONE, t_show_ovs},
+ { KEYWORD, "limit", NONE, t_limit},
+ { KEYWORD, "token", NONE, t_token},
{ FAMILY, "", NONE, t_show_rib},
{ PREFIX, "", NONE, t_show_prefix},
{ ENDTOKEN, "", NONE, NULL}
@@ -461,6 +467,16 @@ static const struct token t_weight[] = {
{ ENDTOKEN, "", NONE, NULL}
};
+static const struct token t_limit[] = {
+ { LIMIT, "", NONE, t_show_rib},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_token[] = {
+ { TOKEN, "", NONE, t_show_rib},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
static const struct token t_log[] = {
{ KEYWORD, "verbose", LOG_VERBOSE, NULL},
{ KEYWORD, "brief", LOG_BRIEF, NULL},
@@ -489,6 +505,7 @@ int parse_number(const char *, struct pa
void parsecommunity(struct community *c, int type, char *s);
void parseextcommunity(struct community *c, const char *t, char *s);
int parse_nexthop(const char *, struct parse_result *);
+int parse_token(const char *, struct ctl_show_rib_token *);
struct parse_result *
parse(int argc, char *argv[])
@@ -561,6 +578,14 @@ match_token(int *argc, char **argv[], co
res.flags |= t->value;
}
break;
+ case ASTYPE:
+ if (word != NULL && strncmp(word, table[i].keyword,
+ wordlen) == 0) {
+ match++;
+ t = &table[i];
+ res.as.type = t->value;
+ }
+ break;
case FAMILY:
if (word == NULL)
break;
@@ -600,19 +625,12 @@ match_token(int *argc, char **argv[], co
}
break;
case PREFIX:
- if (parse_prefix(word, wordlen, &res.addr,
&res.prefixlen)) {
+ if (parse_prefix(word, wordlen, &res.addr,
+ &res.prefixlen)) {
match++;
t = &table[i];
}
break;
- case ASTYPE:
- if (word != NULL && strncmp(word, table[i].keyword,
- wordlen) == 0) {
- match++;
- t = &table[i];
- res.as.type = t->value;
- }
- break;
case ASNUM:
if (parse_asnum(word, wordlen, &res.as.as_min)) {
res.as.as_max = res.as.as_min;
@@ -745,6 +763,7 @@ match_token(int *argc, char **argv[], co
case PREPNBR:
case PREPSELF:
case WEIGHT:
+ case LIMIT:
case RTABLE:
if (word != NULL && wordlen > 0 &&
parse_number(word, &res, table[i].type)) {
@@ -790,6 +809,12 @@ match_token(int *argc, char **argv[], co
t = &table[i];
}
break;
+ case TOKEN:
+ if (parse_token(word, &res.token)) {
+ match++;
+ t = &table[i];
+ }
+ break;
case ENDTOKEN:
break;
}
@@ -861,6 +886,7 @@ show_valid_args(const struct token table
case PREPNBR:
case PREPSELF:
case WEIGHT:
+ case LIMIT:
fprintf(stderr, " <number>\n");
break;
case RTABLE:
@@ -879,6 +905,9 @@ show_valid_args(const struct token table
case FILENAME:
fprintf(stderr, " <filename>\n");
break;
+ case TOKEN:
+ fprintf(stderr, " <token>\n");
+ break;
case ENDTOKEN:
break;
}
@@ -1017,9 +1046,15 @@ parse_number(const char *word, struct pa
errx(1, "number is %s: %s", errstr, word);
/* number was parseable */
- if (type == RTABLE) {
+ switch (type) {
+ case RTABLE:
r->rtableid = uval;
return (1);
+ case LIMIT:
+ r->limit = uval;
+ return (1);
+ default:
+ break;
}
if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
@@ -1383,4 +1418,21 @@ parse_nexthop(const char *word, struct p
TAILQ_INSERT_TAIL(&r->set, fs, entry);
return (1);
+}
+
+int
+parse_token(const char *word, struct ctl_show_rib_token *t)
+{
+ int n;
+
+ memset(t, 0, sizeof(*t));
+ n = sscanf(word, "%d:%hhd:%u:%x:%x:%x:%x:%x:%x:%x:%x:%hhd",
+ &t->peerid, &t->prefix.aid, &t->prefix.scope_id,
+ &t->prefix.addr32[0], &t->prefix.addr32[1], &t->prefix.addr32[2],
+ &t->prefix.addr32[3], &t->prefix.addr32[4], &t->prefix.addr32[5],
+ &t->prefix.addr32[6], &t->prefix.addr32[7], &t->prefixlen);
+
+ if (n == 12)
+ return (1);
+ return (0);
}
Index: bgpctl/parser.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/parser.h,v
retrieving revision 1.38
diff -u -p -r1.38 parser.h
--- bgpctl/parser.h 10 May 2020 13:38:46 -0000 1.38
+++ bgpctl/parser.h 12 May 2020 15:56:15 -0000
@@ -59,6 +59,7 @@ enum actions {
struct parse_result {
struct bgpd_addr addr;
struct bgpd_addr peeraddr;
+ struct ctl_show_rib_token token;
struct filter_as as;
struct filter_set_head set;
struct community community;
@@ -67,14 +68,16 @@ struct parse_result {
char reason[REASON_LEN];
const char *ext_comm_subtype;
u_int64_t rd;
+ u_int32_t limit;
+ u_int rtableid;
int flags;
int is_group;
- u_int8_t validation_state;
- u_int rtableid;
+ int mrtfd;
enum actions action;
+ u_int8_t validation_state;
u_int8_t prefixlen;
+ u_int8_t afterlen;
u_int8_t aid;
- int mrtfd;
};
__dead void usage(void);
Index: bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.403
diff -u -p -r1.403 bgpd.h
--- bgpd/bgpd.h 10 May 2020 13:38:46 -0000 1.403
+++ bgpd/bgpd.h 14 May 2020 15:08:02 -0000
@@ -466,6 +466,7 @@ enum imsg_type {
IMSG_CTL_LOG_VERBOSE,
IMSG_CTL_SHOW_FIB_TABLES,
IMSG_CTL_TERMINATE,
+ IMSG_CTL_TOKEN,
IMSG_NETWORK_ADD,
IMSG_NETWORK_ASPATH,
IMSG_NETWORK_ATTR,
@@ -801,18 +802,26 @@ struct community {
u_int32_t data3;
};
+struct ctl_show_rib_token {
+ u_int32_t peerid;
+ struct bgpd_addr prefix;
+ u_int8_t prefixlen;
+};
+
struct ctl_show_rib_request {
- char rib[PEER_DESCR_LEN];
- struct ctl_neighbor neighbor;
- struct bgpd_addr prefix;
- struct filter_as as;
- struct community community;
- u_int32_t flags;
- u_int8_t validation_state;
- pid_t pid;
- enum imsg_type type;
- u_int8_t prefixlen;
- u_int8_t aid;
+ char rib[PEER_DESCR_LEN];
+ struct ctl_neighbor neighbor;
+ struct bgpd_addr prefix;
+ struct ctl_show_rib_token token;
+ struct filter_as as;
+ struct community community;
+ u_int32_t limit;
+ u_int32_t flags;
+ u_int8_t validation_state;
+ pid_t pid;
+ enum imsg_type type;
+ u_int8_t prefixlen;
+ u_int8_t aid;
};
enum filter_actions {
Index: bgpd/mrt.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/mrt.c,v
retrieving revision 1.103
diff -u -p -r1.103 mrt.c
--- bgpd/mrt.c 9 Jan 2020 11:55:25 -0000 1.103
+++ bgpd/mrt.c 13 May 2020 09:35:43 -0000
@@ -687,7 +687,7 @@ fail:
return (-1);
}
-void
+int
mrt_dump_upcall(struct rib_entry *re, void *ptr)
{
struct mrt *mrtbuf = ptr;
@@ -695,7 +695,7 @@ mrt_dump_upcall(struct rib_entry *re, vo
if (mrtbuf->type == MRT_TABLE_DUMP_V2) {
mrt_dump_entry_v2(mrtbuf, re, mrtbuf->seqnum++);
- return;
+ return 0;
}
/*
@@ -711,6 +711,8 @@ mrt_dump_upcall(struct rib_entry *re, vo
mrt_dump_entry_mp(mrtbuf, p, mrtbuf->seqnum++,
prefix_peer(p));
}
+
+ return 0;
}
void
Index: bgpd/rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.502
diff -u -p -r1.502 rde.c
--- bgpd/rde.c 2 May 2020 14:12:17 -0000 1.502
+++ bgpd/rde.c 14 May 2020 12:59:50 -0000
@@ -73,10 +73,10 @@ void rde_reload_done(void);
static void rde_softreconfig_in_done(void *, u_int8_t);
static void rde_softreconfig_out_done(void *, u_int8_t);
static void rde_softreconfig_done(void);
-static void rde_softreconfig_out(struct rib_entry *, void *);
-static void rde_softreconfig_in(struct rib_entry *, void *);
-static void rde_softreconfig_sync_reeval(struct rib_entry *, void *);
-static void rde_softreconfig_sync_fib(struct rib_entry *, void *);
+static int rde_softreconfig_out(struct rib_entry *, void *);
+static int rde_softreconfig_in(struct rib_entry *, void *);
+static int rde_softreconfig_sync_reeval(struct rib_entry *, void *);
+static int rde_softreconfig_sync_fib(struct rib_entry *, void *);
static void rde_softreconfig_sync_done(void *, u_int8_t);
int rde_update_queue_pending(void);
void rde_update_queue_runner(void);
@@ -92,8 +92,8 @@ static void rde_peer_send_eor(struct rd
void network_add(struct network_config *, struct filterstate *);
void network_delete(struct network_config *);
-static void network_dump_upcall(struct rib_entry *, void *);
-static void network_flush_upcall(struct rib_entry *, void *);
+static int network_dump_upcall(struct rib_entry *, void *);
+static int network_flush_upcall(struct rib_entry *, void *);
void rde_shutdown(void);
int ovs_match(struct prefix *, u_int32_t);
@@ -114,6 +114,7 @@ struct rde_dump_ctx {
LIST_ENTRY(rde_dump_ctx) entry;
struct ctl_show_rib_request req;
u_int32_t peerid;
+ u_int32_t count;
u_int8_t throttled;
};
@@ -2295,109 +2296,154 @@ rde_match_peer(struct rde_peer *p, struc
return 1;
}
-static void
+static int
rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req)
{
struct rde_aspath *asp;
if (!rde_match_peer(prefix_peer(p), &req->neighbor))
- return;
+ return 0;
asp = prefix_aspath(p);
if (asp == NULL) /* skip pending withdraw in Adj-RIB-Out */
- return;
+ return 0;
if ((req->flags & F_CTL_ACTIVE) && p->re->active != p)
- return;
+ return 0;
if ((req->flags & F_CTL_INVALID) &&
(asp->flags & F_ATTR_PARSE_ERR) == 0)
- return;
+ return 0;
if (req->as.type != AS_UNDEF &&
!aspath_match(asp->aspath, &req->as, 0))
- return;
+ return 0;
if (req->community.flags != 0) {
if (!community_match(prefix_communities(p), &req->community,
NULL))
- return;
+ return 0;
}
if (!ovs_match(p, req->flags))
- return;
+ return 0;
+
rde_dump_rib_as(p, asp, req->pid, req->flags);
+ return 1;
}
-static void
+static int
+rde_dump_limit(struct prefix *p, struct rde_dump_ctx *ctx)
+{
+ struct ctl_show_rib_token token;
+
+ ctx->count++;
+ if (ctx->req.limit != 0 && ctx->req.limit <= ctx->count) {
+ token.peerid = ctx->peerid;
+ pt_getaddr(p->pt, &token.prefix);
+ token.prefixlen = p->pt->prefixlen;
+ imsg_compose(ibuf_se_ctl, IMSG_CTL_TOKEN, 0,
+ ctx->req.pid, -1, &token, sizeof(token));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
rde_dump_upcall(struct rib_entry *re, void *ptr)
{
struct rde_dump_ctx *ctx = ptr;
struct prefix *p;
+ int r = 0;
LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
- rde_dump_filter(p, &ctx->req);
+ r |= rde_dump_filter(p, &ctx->req);
+
+ if (r && rde_dump_limit(LIST_FIRST(&re->prefix_h), ctx))
+ return 1;
+
+ return 0;
}
-static void
+static int
rde_dump_prefix_upcall(struct rib_entry *re, void *ptr)
{
struct rde_dump_ctx *ctx = ptr;
struct prefix *p;
struct pt_entry *pt;
struct bgpd_addr addr;
+ int r = 0;
pt = re->prefix;
pt_getaddr(pt, &addr);
if (addr.aid != ctx->req.prefix.aid)
- return;
+ return 0;
if (ctx->req.flags & F_LONGER) {
if (ctx->req.prefixlen > pt->prefixlen)
- return;
+ return 0;
if (!prefix_compare(&ctx->req.prefix, &addr,
ctx->req.prefixlen))
LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
- rde_dump_filter(p, &ctx->req);
+ r |= rde_dump_filter(p, &ctx->req);
} else {
if (ctx->req.prefixlen < pt->prefixlen)
- return;
+ return 0;
if (!prefix_compare(&addr, &ctx->req.prefix,
pt->prefixlen))
LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
- rde_dump_filter(p, &ctx->req);
+ r |= rde_dump_filter(p, &ctx->req);
}
+
+ if (r && rde_dump_limit(LIST_FIRST(&re->prefix_h), ctx))
+ return 1;
+
+ return 0;
}
-static void
+static int
rde_dump_adjout_upcall(struct prefix *p, void *ptr)
{
struct rde_dump_ctx *ctx = ptr;
+ int r = 0;
if (p->flags & (PREFIX_FLAG_WITHDRAW | PREFIX_FLAG_DEAD))
- return;
- rde_dump_filter(p, &ctx->req);
+ return 0;
+
+ r |= rde_dump_filter(p, &ctx->req);
+
+ if (r && rde_dump_limit(p, ctx))
+ return 1;
+
+ return 0;
}
-static void
+static int
rde_dump_adjout_prefix_upcall(struct prefix *p, void *ptr)
{
struct rde_dump_ctx *ctx = ptr;
struct bgpd_addr addr;
+ int r = 0;
if (p->flags & (PREFIX_FLAG_WITHDRAW | PREFIX_FLAG_DEAD))
- return;
+ return 0;
pt_getaddr(p->pt, &addr);
if (addr.aid != ctx->req.prefix.aid)
- return;
+ return 0;
if (ctx->req.flags & F_LONGER) {
if (ctx->req.prefixlen > p->pt->prefixlen)
- return;
+ return 0;
if (!prefix_compare(&ctx->req.prefix, &addr,
ctx->req.prefixlen))
- rde_dump_filter(p, &ctx->req);
+ r |= rde_dump_filter(p, &ctx->req);
} else {
if (ctx->req.prefixlen < p->pt->prefixlen)
- return;
+ return 0;
if (!prefix_compare(&addr, &ctx->req.prefix,
p->pt->prefixlen))
- rde_dump_filter(p, &ctx->req);
+ r |= rde_dump_filter(p, &ctx->req);
}
+
+ if (r && rde_dump_limit(p, ctx))
+ return 1;
+
+ return 0;
}
static int
@@ -2415,6 +2461,9 @@ rde_dump_done(void *arg, u_int8_t aid)
struct rde_peer *peer;
u_int error;
+ if (ctx->req.limit != 0 && ctx->req.limit <= ctx->count)
+ goto done;
+
if (ctx->req.flags & F_CTL_ADJ_OUT) {
peer = peer_match(&ctx->req.neighbor, ctx->peerid);
if (peer == NULL)
@@ -2465,7 +2514,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req
u_int16_t rid;
if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
- nomem:
+nomem:
log_warn(__func__);
error = CTL_RES_NOMEM;
imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error,
@@ -2482,7 +2531,10 @@ rde_dump_ctx_new(struct ctl_show_rib_req
} else if (req->flags & F_CTL_ADJ_OUT) {
struct rde_peer *peer;
- peer = peer_match(&req->neighbor, 0);
+ if (req->token.peerid)
+ peer = peer_get(req->token.peerid);
+ else
+ peer = peer_match(&req->neighbor, req->token.peerid);
if (peer == NULL) {
log_warnx("%s: no peer found for adj-rib-out",
__func__);
@@ -2492,19 +2544,35 @@ rde_dump_ctx_new(struct ctl_show_rib_req
free(ctx);
return;
}
+ /* extract start point from token */
+ p = NULL;
+ if (req->token.prefix.aid != AID_UNSPEC) {
+ if (ctx->req.aid != AID_UNSPEC &&
+ ctx->req.aid != req->token.prefix.aid)
+ /* bad address family */
+ goto done;
+ p = prefix_adjout_getnext(peer, &req->token.prefix,
+ req->token.prefixlen);
+ if (p == NULL) {
+ peer = peer_match(&req->neighbor,
+ peer->conf.id);
+ if (peer == NULL)
+ /* all peers done */
+ goto done;
+ }
+ }
ctx->peerid = peer->conf.id;
switch (ctx->req.type) {
case IMSG_CTL_SHOW_RIB:
- if (prefix_dump_new(peer, ctx->req.aid,
- CTL_MSG_HIGH_MARK, ctx, rde_dump_adjout_upcall,
- rde_dump_done, rde_dump_throttled) == -1)
+ if (prefix_dump_restart(peer, ctx->req.aid, p, ctx,
+ rde_dump_adjout_upcall, rde_dump_done,
+ rde_dump_throttled) == -1)
goto nomem;
break;
case IMSG_CTL_SHOW_RIB_PREFIX:
if (req->flags & (F_LONGER|F_SHORTER)) {
- if (prefix_dump_new(peer, ctx->req.aid,
- CTL_MSG_HIGH_MARK, ctx,
- rde_dump_adjout_prefix_upcall,
+ if (prefix_dump_restart(peer, ctx->req.aid, p,
+ ctx, rde_dump_adjout_prefix_upcall,
rde_dump_done, rde_dump_throttled) == -1)
goto nomem;
break;
@@ -2522,6 +2590,8 @@ rde_dump_ctx_new(struct ctl_show_rib_req
fatalx("%s: unknown af", __func__);
}
+ /* turn off limit, this is considered a single entry. */
+ ctx->req.limit = 0;
do {
if (req->prefixlen == hostplen)
p = prefix_match(peer, &req->prefix);
@@ -2533,10 +2603,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req
} while ((peer = peer_match(&req->neighbor,
peer->conf.id)));
- imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid,
- -1, NULL, 0);
- free(ctx);
- return;
+ goto done;
default:
fatalx("%s: unsupported imsg type", __func__);
}
@@ -2552,23 +2619,36 @@ rde_dump_ctx_new(struct ctl_show_rib_req
return;
}
+ /* extract start point from token */
+ re = NULL;
+ if (req->token.prefix.aid != AID_UNSPEC) {
+ if (ctx->req.aid != AID_UNSPEC &&
+ ctx->req.aid != req->token.prefix.aid)
+ /* bad address family */
+ goto done;
+ re = rib_getnext(rib_byid(rid), &req->token.prefix,
+ req->token.prefixlen);
+ if (re == NULL)
+ /* no next prefix found */
+ goto done;
+ }
switch (ctx->req.type) {
case IMSG_CTL_SHOW_NETWORK:
- if (rib_dump_new(rid, ctx->req.aid, CTL_MSG_HIGH_MARK, ctx,
+ if (rib_dump_restart(rid, ctx->req.aid, re, ctx,
network_dump_upcall, rde_dump_done,
rde_dump_throttled) == -1)
goto nomem;
break;
case IMSG_CTL_SHOW_RIB:
- if (rib_dump_new(rid, ctx->req.aid, CTL_MSG_HIGH_MARK, ctx,
+ if (rib_dump_restart(rid, ctx->req.aid, re, ctx,
rde_dump_upcall, rde_dump_done, rde_dump_throttled) == -1)
goto nomem;
break;
case IMSG_CTL_SHOW_RIB_PREFIX:
if (req->flags & (F_LONGER|F_SHORTER)) {
- if (rib_dump_new(rid, ctx->req.aid,
- CTL_MSG_HIGH_MARK, ctx, rde_dump_prefix_upcall,
- rde_dump_done, rde_dump_throttled) == -1)
+ if (rib_dump_restart(rid, ctx->req.aid, re, ctx,
+ rde_dump_prefix_upcall, rde_dump_done,
+ rde_dump_throttled) == -1)
goto nomem;
break;
}
@@ -2591,6 +2671,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req
req->prefixlen);
if (re)
rde_dump_upcall(re, ctx);
+done:
imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid,
-1, NULL, 0);
free(ctx);
@@ -2796,10 +2877,11 @@ rde_generate_updates(struct rib *rib, st
}
}
-static void
+static int
rde_up_flush_upcall(struct prefix *p, void *ptr)
{
up_generate_updates(out_rules, prefix_peer(p), NULL, p);
+ return 0;
}
u_char queue_buf[4096];
@@ -3299,7 +3381,7 @@ rde_softreconfig_done(void)
-1, NULL, 0);
}
-static void
+static int
rde_softreconfig_in(struct rib_entry *re, void *bula)
{
struct filterstate state;
@@ -3361,9 +3443,11 @@ rde_softreconfig_in(struct rib_entry *re
rde_filterstate_clean(&state);
}
}
+
+ return 0;
}
-static void
+static int
rde_softreconfig_out(struct rib_entry *re, void *bula)
{
struct prefix *p = re->active;
@@ -3371,16 +3455,18 @@ rde_softreconfig_out(struct rib_entry *r
if (p == NULL)
/* no valid path for prefix */
- return;
+ return 0;
LIST_FOREACH(peer, &peerlist, peer_l) {
if (peer->loc_rib_id == re->rib_id && peer->reconf_out)
/* Regenerate all updates. */
up_generate_updates(out_rules, peer, p, p);
}
+
+ return 0;
}
-static void
+static int
rde_softreconfig_sync_reeval(struct rib_entry *re, void *arg)
{
struct prefix_list prefixes;
@@ -3401,7 +3487,7 @@ rde_softreconfig_sync_reeval(struct rib_
rde_generate_updates(rib, NULL, re->active);
re->active = NULL;
}
- return;
+ return 0;
}
/* evaluation process is turned on, so evaluate all prefixes again */
@@ -3416,13 +3502,16 @@ rde_softreconfig_sync_reeval(struct rib_
LIST_REMOVE(p, entry.list.rib);
prefix_evaluate(p, re);
}
+
+ return 0;
}
-static void
+static int
rde_softreconfig_sync_fib(struct rib_entry *re, void *bula)
{
if (re->active)
rde_send_kroute(re_rib(re), re->active, NULL);
+ return 0;
}
static void
@@ -3688,7 +3777,7 @@ network_delete(struct network_config *nc
rde_send_pftable_commit();
}
-static void
+static int
network_dump_upcall(struct rib_entry *re, void *ptr)
{
struct prefix *p;
@@ -3720,9 +3809,11 @@ network_dump_upcall(struct rib_entry *re
log_warnx("network_dump_upcall: "
"imsg_compose error");
}
+
+ return 0;
}
-static void
+static int
network_flush_upcall(struct rib_entry *re, void *ptr)
{
struct rde_peer *peer = ptr;
@@ -3733,9 +3824,9 @@ network_flush_upcall(struct rib_entry *r
p = prefix_bypeer(re, peer);
if (p == NULL)
- return;
+ return 0;
if ((prefix_aspath(p)->flags & F_ANN_DYNAMIC) != F_ANN_DYNAMIC)
- return;
+ return 0;
pt_getaddr(re->prefix, &addr);
prefixlen = re->prefix->prefixlen;
@@ -3752,6 +3843,8 @@ network_flush_upcall(struct rib_entry *r
if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peer, &addr,
prefixlen) == 1)
peer->prefix_cnt--;
+
+ return 0;
}
/* clean up */
Index: bgpd/rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.233
diff -u -p -r1.233 rde.h
--- bgpd/rde.h 24 Jan 2020 05:44:05 -0000 1.233
+++ bgpd/rde.h 14 May 2020 11:50:37 -0000
@@ -357,7 +357,7 @@ extern struct rde_memstats rdemem;
/* mrt.c */
int mrt_dump_v2_hdr(struct mrt *, struct bgpd_config *,
struct rde_peer_head *);
-void mrt_dump_upcall(struct rib_entry *, void *);
+int mrt_dump_upcall(struct rib_entry *, void *);
/* rde.c */
void rde_update_err(struct rde_peer *, u_int8_t , u_int8_t,
@@ -541,11 +541,16 @@ u_int16_t rib_find(char *);
void rib_free(struct rib *);
void rib_shutdown(void);
struct rib_entry *rib_get(struct rib *, struct bgpd_addr *, int);
+struct rib_entry *rib_getnext(struct rib *, struct bgpd_addr *, int);
struct rib_entry *rib_match(struct rib *, struct bgpd_addr *);
int rib_dump_pending(void);
void rib_dump_runner(void);
int rib_dump_new(u_int16_t, u_int8_t, unsigned int, void *,
- void (*)(struct rib_entry *, void *),
+ int (*)(struct rib_entry *, void *),
+ void (*)(void *, u_int8_t),
+ int (*)(void *));
+int rib_dump_restart(u_int16_t, u_int8_t, struct rib_entry *,
+ void *, int (*)(struct rib_entry *, void *),
void (*)(void *, u_int8_t),
int (*)(void *));
void rib_dump_terminate(void *);
@@ -582,11 +587,16 @@ int prefix_adjout_update(struct rde_pe
struct bgpd_addr *, int, u_int8_t);
int prefix_adjout_withdraw(struct rde_peer *, struct bgpd_addr *,
int);
+struct prefix *prefix_adjout_getnext(struct rde_peer *, struct bgpd_addr *,
+ int);
void prefix_adjout_destroy(struct prefix *p);
void prefix_adjout_dump(struct rde_peer *, void *,
void (*)(struct prefix *, void *));
int prefix_dump_new(struct rde_peer *, u_int8_t, unsigned int,
- void *, void (*)(struct prefix *, void *),
+ void *, int (*)(struct prefix *, void *),
+ void (*)(void *, u_int8_t), int (*)(void *));
+int prefix_dump_restart(struct rde_peer *, u_int8_t,
+ struct prefix *, void *, int (*)(struct prefix *, void *),
void (*)(void *, u_int8_t), int (*)(void *));
int prefix_write(u_char *, int, struct bgpd_addr *, u_int8_t, int);
int prefix_writebuf(struct ibuf *, struct bgpd_addr *, u_int8_t);
Index: bgpd/rde_peer.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v
retrieving revision 1.5
diff -u -p -r1.5 rde_peer.c
--- bgpd/rde_peer.c 12 Feb 2020 10:33:56 -0000 1.5
+++ bgpd/rde_peer.c 14 May 2020 11:42:12 -0000
@@ -183,26 +183,28 @@ peer_add(u_int32_t id, struct peer_confi
/*
* Various RIB walker callbacks.
*/
-static void
+static int
peer_adjout_clear_upcall(struct prefix *p, void *arg)
{
prefix_adjout_destroy(p);
+ return 0;
}
-static void
+static int
peer_adjout_stale_upcall(struct prefix *p, void *arg)
{
if (p->flags & PREFIX_FLAG_DEAD) {
- return;
+ return 0;
} else if (p->flags & PREFIX_FLAG_WITHDRAW) {
/* no need to keep stale withdraws, they miss all attributes */
prefix_adjout_destroy(p);
- return;
+ return 0;
} else if (p->flags & PREFIX_FLAG_UPDATE) {
RB_REMOVE(prefix_tree, &prefix_peer(p)->updates[p->pt->aid], p);
p->flags &= ~PREFIX_FLAG_UPDATE;
}
p->flags |= PREFIX_FLAG_STALE;
+ return 0;
}
struct peer_flush {
@@ -210,7 +212,7 @@ struct peer_flush {
time_t staletime;
};
-static void
+static int
peer_flush_upcall(struct rib_entry *re, void *arg)
{
struct rde_peer *peer = ((struct peer_flush *)arg)->peer;
@@ -250,9 +252,11 @@ peer_flush_upcall(struct rib_entry *re,
peer->prefix_cnt--;
break; /* optimization, only one match per peer possible */
}
+
+ return 0;
}
-static void
+static int
rde_up_adjout_force_upcall(struct prefix *p, void *ptr)
{
if (p->flags & PREFIX_FLAG_STALE) {
@@ -267,6 +271,7 @@ rde_up_adjout_force_upcall(struct prefix
p) != NULL)
fatalx("%s: RB tree invariant violated", __func__);
}
+ return 0;
}
static void
@@ -280,7 +285,7 @@ rde_up_adjout_force_done(void *ptr, u_in
prefix_add_eor(peer, aid);
}
-static void
+static int
rde_up_dump_upcall(struct rib_entry *re, void *ptr)
{
struct rde_peer *peer = ptr;
@@ -289,8 +294,9 @@ rde_up_dump_upcall(struct rib_entry *re,
fatalx("%s: Unexpected RIB %u != %u.", __func__, re->rib_id,
peer->loc_rib_id);
if (re->active == NULL)
- return;
+ return 0;
up_generate_updates(out_rules, peer, re->active, NULL);
+ return 0;
}
static void
Index: bgpd/rde_rib.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
retrieving revision 1.215
diff -u -p -r1.215 rde_rib.c
--- bgpd/rde_rib.c 25 Jan 2020 23:54:21 -0000 1.215
+++ bgpd/rde_rib.c 14 May 2020 11:58:30 -0000
@@ -54,8 +54,8 @@ struct rib_context {
struct rib_entry *ctx_re;
struct prefix *ctx_p;
u_int32_t ctx_id;
- void (*ctx_rib_call)(struct rib_entry *, void *);
- void (*ctx_prefix_call)(struct prefix *, void *);
+ int (*ctx_rib_call)(struct rib_entry *, void *);
+ int (*ctx_prefix_call)(struct prefix *, void *);
void (*ctx_done)(void *, u_int8_t);
int (*ctx_throttle)(void *);
void *ctx_arg;
@@ -64,7 +64,7 @@ struct rib_context {
};
LIST_HEAD(, rib_context) rib_dumps = LIST_HEAD_INITIALIZER(rib_dumps);
-static void prefix_dump_r(struct rib_context *);
+static void prefix_dump_r(struct rib_context *, struct prefix *);
static inline struct rib_entry *
re_lock(struct rib_entry *re)
@@ -299,6 +299,7 @@ rib_shutdown(void)
free(ribs);
}
+/* Find rib_entry matching prefix. */
struct rib_entry *
rib_get(struct rib *rib, struct bgpd_addr *prefix, int prefixlen)
{
@@ -316,6 +317,25 @@ rib_get(struct rib *rib, struct bgpd_add
return re;
}
+/* Find the next rib_entry that is grater than prefix. */
+struct rib_entry *
+rib_getnext(struct rib *rib, struct bgpd_addr *prefix, int prefixlen)
+{
+ struct rib_entry xre, *re;
+ struct pt_entry *pte;
+
+ pte = pt_fill(prefix, prefixlen);
+ memset(&xre, 0, sizeof(xre));
+ xre.prefix = pte;
+
+ re = RB_NFIND(rib_tree, rib_tree(rib), &xre);
+ if (re && rib_compare(re, &xre) == 0)
+ re = RB_NEXT(rib_tree, unused, re);
+
+ return re;
+}
+
+/* Find longest prefix matching addr. */
struct rib_entry *
rib_match(struct rib *rib, struct bgpd_addr *addr)
{
@@ -419,22 +439,25 @@ rib_restart(struct rib_context *ctx)
}
static void
-rib_dump_r(struct rib_context *ctx)
+rib_dump_r(struct rib_context *ctx, struct rib_entry *start)
{
struct rib_entry *re, *next;
struct rib *rib;
- unsigned int i;
+ unsigned int i = 0;
rib = rib_byid(ctx->ctx_id);
if (rib == NULL)
fatalx("%s: rib id %u gone", __func__, ctx->ctx_id);
- if (ctx->ctx_re == NULL)
+ if (start != NULL) {
+ re = start;
+ i = ctx->ctx_count; /* park call as soon as possible */
+ } else if (ctx->ctx_re == NULL)
re = RB_MIN(rib_tree, rib_tree(rib));
else
re = rib_restart(ctx);
- for (i = 0; re != NULL; re = next) {
+ for (; re != NULL; re = next) {
next = RB_NEXT(rib_tree, unused, re);
if (re->rib_id != ctx->ctx_id)
fatalx("%s: Unexpected RIB %u != %u.", __func__,
@@ -448,7 +471,8 @@ rib_dump_r(struct rib_context *ctx)
ctx->ctx_re = re_lock(re);
return;
}
- ctx->ctx_rib_call(re, ctx->ctx_arg);
+ if (ctx->ctx_rib_call(re, ctx->ctx_arg))
+ break;
}
if (ctx->ctx_done)
@@ -480,9 +504,9 @@ rib_dump_runner(void)
if (ctx->ctx_throttle && ctx->ctx_throttle(ctx->ctx_arg))
continue;
if (ctx->ctx_rib_call != NULL)
- rib_dump_r(ctx);
+ rib_dump_r(ctx, NULL);
else
- prefix_dump_r(ctx);
+ prefix_dump_r(ctx, NULL);
}
}
@@ -526,7 +550,7 @@ rib_dump_terminate(void *arg)
int
rib_dump_new(u_int16_t id, u_int8_t aid, unsigned int count, void *arg,
- void (*upcall)(struct rib_entry *, void *), void (*done)(void *, u_int8_t),
+ int (*upcall)(struct rib_entry *, void *), void (*done)(void *, u_int8_t),
int (*throttle)(void *))
{
struct rib_context *ctx;
@@ -545,7 +569,32 @@ rib_dump_new(u_int16_t id, u_int8_t aid,
/* requested a sync traversal */
if (count == 0)
- rib_dump_r(ctx);
+ rib_dump_r(ctx, NULL);
+
+ return 0;
+}
+
+int
+rib_dump_restart(u_int16_t id, u_int8_t aid, struct rib_entry *re, void *arg,
+ int (*upcall)(struct rib_entry *, void *), void (*done)(void *, u_int8_t),
+ int (*throttle)(void *))
+{
+ struct rib_context *ctx;
+
+ if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
+ return -1;
+ ctx->ctx_id = id;
+ ctx->ctx_aid = aid;
+ ctx->ctx_count = CTL_MSG_HIGH_MARK;
+ ctx->ctx_arg = arg;
+ ctx->ctx_rib_call = upcall;
+ ctx->ctx_done = done;
+ ctx->ctx_throttle = throttle;
+
+ LIST_INSERT_HEAD(&rib_dumps, ctx, entry);
+
+ if (re)
+ rib_dump_r(ctx, re);
return 0;
}
@@ -895,7 +944,7 @@ RB_GENERATE(prefix_tree, prefix, entry.t
RB_GENERATE_STATIC(prefix_index, prefix, entry.tree.index, prefix_index_cmp)
/*
- * search for specified prefix of a peer. Returns NULL if not found.
+ * Search for specified prefix of a peer. Returns NULL if not found.
*/
struct prefix *
prefix_get(struct rib *rib, struct rde_peer *peer, struct bgpd_addr *prefix,
@@ -1275,6 +1324,29 @@ prefix_adjout_withdraw(struct rde_peer *
return (1);
}
+/*
+ * Search for the next prefix after the one specified.
+ * Returns NULL if not found.
+ */
+struct prefix *
+prefix_adjout_getnext(struct rde_peer *peer, struct bgpd_addr *prefix,
+ int prefixlen)
+{
+ struct prefix xp, *p;
+ struct pt_entry *pte;
+
+ memset(&xp, 0, sizeof(xp));
+ pte = pt_fill(prefix, prefixlen);
+ xp.pt = pte;
+
+ p = RB_FIND(prefix_index, &peer->adj_rib_out, &xp);
+ if (p && prefix_index_cmp(p, &xp) == 0)
+ p = RB_NEXT(prefix_index, unused, p);
+
+ return p;
+}
+
+
static struct prefix *
prefix_restart(struct rib_context *ctx)
{
@@ -1337,21 +1409,24 @@ prefix_adjout_destroy(struct prefix *p)
}
static void
-prefix_dump_r(struct rib_context *ctx)
+prefix_dump_r(struct rib_context *ctx, struct prefix *start)
{
struct prefix *p, *next;
struct rde_peer *peer;
- unsigned int i;
+ unsigned int i = 0;
if ((peer = peer_get(ctx->ctx_id)) == NULL)
goto done;
- if (ctx->ctx_p == NULL)
+ if (start != NULL) {
+ p = start;
+ i = ctx->ctx_count; /* park call as soon as possible */
+ } else if (ctx->ctx_p == NULL)
p = RB_MIN(prefix_index, &peer->adj_rib_out);
else
p = prefix_restart(ctx);
- for (i = 0; p != NULL; p = next) {
+ for (; p != NULL; p = next) {
next = RB_NEXT(prefix_index, unused, p);
if (prefix_is_dead(p))
continue;
@@ -1364,7 +1439,8 @@ prefix_dump_r(struct rib_context *ctx)
ctx->ctx_p = prefix_lock(p);
return;
}
- ctx->ctx_prefix_call(p, ctx->ctx_arg);
+ if (ctx->ctx_prefix_call(p, ctx->ctx_arg))
+ break;
}
done:
@@ -1376,7 +1452,7 @@ done:
int
prefix_dump_new(struct rde_peer *peer, u_int8_t aid, unsigned int count,
- void *arg, void (*upcall)(struct prefix *, void *),
+ void *arg, int (*upcall)(struct prefix *, void *),
void (*done)(void *, u_int8_t), int (*throttle)(void *))
{
struct rib_context *ctx;
@@ -1395,7 +1471,33 @@ prefix_dump_new(struct rde_peer *peer, u
/* requested a sync traversal */
if (count == 0)
- prefix_dump_r(ctx);
+ prefix_dump_r(ctx, NULL);
+
+ return 0;
+}
+
+int
+prefix_dump_restart(struct rde_peer *peer, u_int8_t aid, struct prefix *p,
+ void *arg, int (*upcall)(struct prefix *, void *),
+ void (*done)(void *, u_int8_t), int (*throttle)(void *))
+{
+ struct rib_context *ctx;
+
+ if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
+ return -1;
+ ctx->ctx_id = peer->conf.id;
+ ctx->ctx_aid = aid;
+ ctx->ctx_count = CTL_MSG_HIGH_MARK;
+ ctx->ctx_arg = arg;
+ ctx->ctx_prefix_call = upcall;
+ ctx->ctx_done = done;
+ ctx->ctx_throttle = throttle;
+
+ LIST_INSERT_HEAD(&rib_dumps, ctx, entry);
+
+ /* requested a sync traversal */
+ if (p)
+ prefix_dump_r(ctx, p);
return 0;
}
Index: bgpd/session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.401
diff -u -p -r1.401 session.c
--- bgpd/session.c 10 May 2020 13:38:46 -0000 1.401
+++ bgpd/session.c 12 May 2020 15:53:59 -0000
@@ -2829,6 +2829,7 @@ session_dispatch_imsg(struct imsgbuf *ib
fatalx("ctl rib request not from RDE");
control_imsg_relay(&imsg);
break;
+ case IMSG_CTL_TOKEN:
case IMSG_CTL_END:
case IMSG_CTL_RESULT:
control_imsg_relay(&imsg);