Claudio Jeker(cje...@diehard.n-r-g.com) on 2019.01.20 12:33:29 +0100: > In many cases it is nice to be able to use a command against a group of > neighbors (e.g. all exchange peers). This diff implements this for > bgpctl neighbor group foo [clear|destroy|down|refresh|up] > bgpctl show neighbor group foo [messages|terse|timers] > bgpctl show rib neighbor group foo ... > This should cover all cases. > > The bgpctl manpage probably needs some extra love.
the manpage part has whitspace problems: behind every "with" there is a space. one more comment below, otherwise ok benno@ > -- > :wq Claudio > > Index: bgpctl/bgpctl.8 > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.8,v > retrieving revision 1.84 > diff -u -p -r1.84 bgpctl.8 > --- bgpctl/bgpctl.8 12 Dec 2018 20:21:04 -0000 1.84 > +++ bgpctl/bgpctl.8 20 Jan 2019 11:26:54 -0000 > @@ -116,12 +116,14 @@ The > .Ar reason > cannot exceed 128 octets. > .Ar peer > -may be the neighbor's address or description. > +may be the neighbor's address, description or a group description used with > +.Cm group . > .It Cm neighbor Ar peer Cm destroy > Destroy a previously cloned peer. > The peer must be down before calling this function. > .Ar peer > -may be the neighbor's address or description. > +may be the neighbor's address, description or a group description used with > +.Cm group . > .It Cm neighbor Ar peer Cm down Op Ar reason > Take the BGP session to the specified neighbor down. > If a > @@ -133,17 +135,20 @@ The > .Ar reason > cannot exceed 128 octets. > .Ar peer > -may be the neighbor's address or description. > +may be the neighbor's address, description or a group description used with > +.Cm group . > .It Cm neighbor Ar peer Cm refresh > Request the neighbor to re-send all routes. > Note that the neighbor is not obliged to re-send all routes, or any routes at > all, even if it announced the route refresh capability. > .Ar peer > -may be the neighbor's address or description. > +may be the neighbor's address, description or a group description used with > +.Cm group . > .It Cm neighbor Ar peer Cm up > Bring the BGP session to the specified neighbor up. > .Ar peer > -may be the neighbor's address or description. > +may be the neighbor's address, description or a group description used with > +.Cm group . > .It Cm network add Ar prefix Op Ar arguments > Add the specified prefix to the list of announced networks. > It is possible to set various path attributes with additional > @@ -283,7 +288,9 @@ Multiple options and filters can be used > .It Cm show neighbor Ar peer modifier > Show detailed information about the neighbor identified by > .Ar peer , > -which may be the neighbor's address or description, > +which may be the neighbor's address, description or a group description used > +with > +.Cm group , > according to the given > .Ar modifier : > .Pp > @@ -339,6 +346,8 @@ Show all entries that are internal route > Show RIB memory statistics. > .It Cm neighbor Ar peer > Show only entries from the specified peer. > +.It Cm neighbor group Ar description > +Show only entries from the specified peer group. > .It Cm peer-as Ar as > Show all entries with > .Ar as > Index: bgpctl/bgpctl.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v > retrieving revision 1.227 > diff -u -p -r1.227 bgpctl.c > --- bgpctl/bgpctl.c 19 Dec 2018 15:27:29 -0000 1.227 > +++ bgpctl/bgpctl.c 20 Jan 2019 05:22:03 -0000 > @@ -156,6 +156,7 @@ main(int argc, char *argv[]) > > memcpy(&neighbor.addr, &res->peeraddr, sizeof(neighbor.addr)); > strlcpy(neighbor.descr, res->peerdesc, sizeof(neighbor.descr)); > + neighbor.is_group = res->is_group; > strlcpy(neighbor.shutcomm, res->shutcomm, sizeof(neighbor.shutcomm)); > > switch (res->action) { > Index: bgpctl/parser.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v > retrieving revision 1.88 > diff -u -p -r1.88 parser.c > --- bgpctl/parser.c 19 Dec 2018 15:27:29 -0000 1.88 > +++ bgpctl/parser.c 20 Jan 2019 05:20:23 -0000 > @@ -44,6 +44,7 @@ enum token_type { > ASTYPE, > PREFIX, > PEERDESC, > + GROUPDESC, > RIBNAME, > SHUTDOWN_COMMUNICATION, > COMMUNITY, > @@ -220,7 +221,13 @@ static const struct token t_show_mrt_fil > { ENDTOKEN, "", NONE, NULL} > }; > > +static const struct token t_show_rib_neigh_group[] = { > + { GROUPDESC, "", NONE, t_show_rib}, > + { ENDTOKEN, "", NONE, NULL} > +}; > + > static const struct token t_show_rib_neigh[] = { > + { KEYWORD, "group", NONE, t_show_rib_neigh_group}, > { PEERADDRESS, "", NONE, t_show_rib}, > { PEERDESC, "", NONE, t_show_rib}, > { ENDTOKEN, "", NONE, NULL} > @@ -236,13 +243,6 @@ static const struct token t_show_rib_rib > { ENDTOKEN, "", NONE, NULL} > }; > > -static const struct token t_show_neighbor[] = { > - { NOTOKEN, "", NONE, NULL}, > - { PEERADDRESS, "", NONE, t_show_neighbor_modifiers}, > - { PEERDESC, "", NONE, t_show_neighbor_modifiers}, > - { ENDTOKEN, "", NONE, NULL} > -}; > - > static const struct token t_show_neighbor_modifiers[] = { > { NOTOKEN, "", NONE, NULL}, > { KEYWORD, "timers", SHOW_NEIGHBOR_TIMERS, NULL}, > @@ -251,6 +251,19 @@ static const struct token t_show_neighbo > { ENDTOKEN, "", NONE, NULL} > }; > > +static const struct token t_show_neighbor_group[] = { > + { GROUPDESC, "", NONE, t_show_neighbor_modifiers}, > + { ENDTOKEN, "", NONE, NULL} > +}; > + > +static const struct token t_show_neighbor[] = { > + { NOTOKEN, "", NONE, NULL}, > + { KEYWORD, "group", NONE, t_show_neighbor_group}, > + { PEERADDRESS, "", NONE, t_show_neighbor_modifiers}, > + { PEERDESC, "", NONE, t_show_neighbor_modifiers}, > + { ENDTOKEN, "", NONE, NULL} > +}; > + > static const struct token t_fib[] = { > { KEYWORD, "couple", FIB_COUPLE, NULL}, > { KEYWORD, "decouple", FIB_DECOUPLE, NULL}, > @@ -258,7 +271,13 @@ static const struct token t_fib[] = { > { ENDTOKEN, "", NONE, NULL} > }; > > +static const struct token t_neighbor_group[] = { > + { GROUPDESC, "", NONE, t_neighbor_modifiers}, > + { ENDTOKEN, "", NONE, NULL} > +}; > + > static const struct token t_neighbor[] = { > + { KEYWORD, "group", NONE, t_neighbor_group}, > { PEERADDRESS, "", NONE, t_neighbor_modifiers}, > { PEERDESC, "", NONE, t_neighbor_modifiers}, > { ENDTOKEN, "", NONE, NULL} > @@ -622,6 +641,9 @@ match_token(int *argc, char **argv[], co > t = &table[i]; > } > break; > + case GROUPDESC: > + res.is_group = 1; > + /* FALLTHROUGH */ > case PEERDESC: > if (!match && word != NULL && wordlen > 0) { > if (strlcpy(res.peerdesc, word, > @@ -788,6 +810,7 @@ show_valid_args(const struct token table > case ASNUM: > fprintf(stderr, " <asnum>\n"); > break; > + case GROUPDESC: > case PEERDESC: > fprintf(stderr, " <neighbor description>\n"); > break; > Index: bgpctl/parser.h > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpctl/parser.h,v > retrieving revision 1.33 > diff -u -p -r1.33 parser.h > --- bgpctl/parser.h 19 Dec 2018 15:27:29 -0000 1.33 > +++ bgpctl/parser.h 20 Jan 2019 05:11:57 -0000 > @@ -68,6 +68,7 @@ struct parse_result { > char shutcomm[SHUT_COMM_LEN]; > char *irr_outdir; > int flags; > + int is_group; > u_int8_t validation_state; > u_int rtableid; > enum actions action; > Index: bgpd/bgpd.h > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v > retrieving revision 1.362 > diff -u -p -r1.362 bgpd.h > --- bgpd/bgpd.h 18 Jan 2019 23:30:45 -0000 1.362 > +++ bgpd/bgpd.h 20 Jan 2019 06:26:44 -0000 > @@ -668,6 +668,7 @@ struct ctl_neighbor { > char descr[PEER_DESCR_LEN]; > char shutcomm[SHUT_COMM_LEN]; > int show_timers; > + int is_group; > }; > > #define F_PREF_ELIGIBLE 0x01 > @@ -781,7 +782,6 @@ struct ctl_show_rib_request { > struct bgpd_addr prefix; > struct filter_as as; > struct filter_community community; > - u_int32_t peerid; > u_int32_t flags; > u_int8_t validation_state; > pid_t pid; > Index: bgpd/control.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/control.c,v > retrieving revision 1.93 > diff -u -p -r1.93 control.c > --- bgpd/control.c 27 Dec 2018 20:23:24 -0000 1.93 > +++ bgpd/control.c 20 Jan 2019 06:41:03 -0000 > @@ -225,7 +225,7 @@ control_dispatch_msg(struct pollfd *pfd, > struct imsg imsg; > struct ctl_conn *c; > ssize_t n; > - int verbose; > + int verbose, matched; > struct peer *p; > struct ctl_neighbor *neighbor; > struct ctl_show_rib_request *ribreq; > @@ -288,24 +288,36 @@ control_dispatch_msg(struct pollfd *pfd, > case IMSG_NONE: > /* message was filtered out, nothing to do */ > break; > + case IMSG_CTL_FIB_COUPLE: > + case IMSG_CTL_FIB_DECOUPLE: > + imsg_ctl_parent(imsg.hdr.type, imsg.hdr.peerid, > + 0, NULL, 0); > + break; > + case IMSG_CTL_SHOW_TERSE: > + for (p = peers; p != NULL; p = p->next) > + imsg_compose(&c->ibuf, IMSG_CTL_SHOW_NEIGHBOR, > + 0, 0, -1, p, sizeof(struct peer)); > + imsg_compose(&c->ibuf, IMSG_CTL_END, 0, 0, -1, NULL, 0); > + break; > case IMSG_CTL_SHOW_NEIGHBOR: > c->ibuf.pid = imsg.hdr.pid; > + > if (imsg.hdr.len == IMSG_HEADER_SIZE + > sizeof(struct ctl_neighbor)) { > neighbor = imsg.data; > - p = getpeerbyaddr(&neighbor->addr); > - if (p == NULL) > - p = getpeerbydesc(neighbor->descr); > - if (p == NULL) { > - control_result(c, CTL_RES_NOSUCHPEER); > - break; > - } > - if (!neighbor->show_timers) { > + neighbor->descr[PEER_DESCR_LEN - 1] = 0; > + } else { > + neighbor = NULL; > + } > + for (matched = 0, p = peers; p != NULL; p = p->next) { > + if (!peer_matched(p, neighbor)) > + continue; > + > + matched = 1; > + if (!neighbor || !neighbor->show_timers) { > imsg_ctl_rde(imsg.hdr.type, > imsg.hdr.pid, > p, sizeof(struct peer)); > - imsg_ctl_rde(IMSG_CTL_END, > - imsg.hdr.pid, NULL, 0); > } else { > u_int i; > time_t d; > @@ -323,45 +335,39 @@ control_dispatch_msg(struct pollfd *pfd, > IMSG_CTL_SHOW_TIMER, > 0, 0, -1, &ct, sizeof(ct)); > } > - imsg_compose(&c->ibuf, IMSG_CTL_END, > - 0, 0, -1, NULL, 0); > } > - } else { > - for (p = peers; p != NULL; p = p->next) > - imsg_ctl_rde(imsg.hdr.type, > - imsg.hdr.pid, > - p, sizeof(struct peer)); > + } > + if (!matched) { > + control_result(c, CTL_RES_NOSUCHPEER); > + } else if (!neighbor || !neighbor->show_timers) { > imsg_ctl_rde(IMSG_CTL_END, imsg.hdr.pid, > - NULL, 0); > + NULL, 0); > + } else { > + imsg_compose(&c->ibuf, IMSG_CTL_END, 0, 0, -1, > + NULL, 0); > } > break; > - case IMSG_CTL_SHOW_TERSE: > - for (p = peers; p != NULL; p = p->next) > - imsg_compose(&c->ibuf, IMSG_CTL_SHOW_NEIGHBOR, > - 0, 0, -1, p, sizeof(struct peer)); > - imsg_compose(&c->ibuf, IMSG_CTL_END, 0, 0, -1, NULL, 0); > - break; > - case IMSG_CTL_FIB_COUPLE: > - case IMSG_CTL_FIB_DECOUPLE: > - imsg_ctl_parent(imsg.hdr.type, imsg.hdr.peerid, > - 0, NULL, 0); > - break; > case IMSG_CTL_NEIGHBOR_UP: > case IMSG_CTL_NEIGHBOR_DOWN: > case IMSG_CTL_NEIGHBOR_CLEAR: > case IMSG_CTL_NEIGHBOR_RREFRESH: > case IMSG_CTL_NEIGHBOR_DESTROY: > - if (imsg.hdr.len == IMSG_HEADER_SIZE + > + if (imsg.hdr.len != IMSG_HEADER_SIZE + > sizeof(struct ctl_neighbor)) { > - neighbor = imsg.data; > - neighbor->descr[PEER_DESCR_LEN - 1] = 0; > - p = getpeerbyaddr(&neighbor->addr); > - if (p == NULL) > - p = getpeerbydesc(neighbor->descr); > - if (p == NULL) { > - control_result(c, CTL_RES_NOSUCHPEER); > - break; > - } > + log_warnx("got IMSG_CTL_NEIGHBOR_ with " > + "wrong length"); > + break; > + } > + > + neighbor = imsg.data; > + neighbor->descr[PEER_DESCR_LEN - 1] = 0; > + > + for (matched = 0, p = peers; p != NULL; p = p->next) { > + if (!peer_matched(p, neighbor)) > + continue; > + > + matched = 1; > + > switch (imsg.hdr.type) { > case IMSG_CTL_NEIGHBOR_UP: > bgp_fsm(p, EVNT_START); > @@ -419,9 +425,9 @@ control_dispatch_msg(struct pollfd *pfd, > default: > fatal("king bula wants more humppa"); > } > - } else > - log_warnx("got IMSG_CTL_NEIGHBOR_ with " > - "wrong length"); > + } > + if (!matched) > + control_result(c, CTL_RES_NOSUCHPEER); > break; > case IMSG_CTL_RELOAD: > case IMSG_CTL_SHOW_INTERFACE: > @@ -440,53 +446,38 @@ control_dispatch_msg(struct pollfd *pfd, > break; > case IMSG_CTL_SHOW_RIB: > case IMSG_CTL_SHOW_RIB_PREFIX: > - if (imsg.hdr.len == IMSG_HEADER_SIZE + > + if (imsg.hdr.len != IMSG_HEADER_SIZE + > sizeof(struct ctl_show_rib_request)) { > - ribreq = imsg.data; > - neighbor = &ribreq->neighbor; > - neighbor->descr[PEER_DESCR_LEN - 1] = 0; > - ribreq->peerid = 0; > - p = NULL; > - if (neighbor->addr.aid) { > - p = getpeerbyaddr(&neighbor->addr); > - if (p == NULL) { > - control_result(c, > - CTL_RES_NOSUCHPEER); > - break; > - } > - ribreq->peerid = p->conf.id; > - } else if (neighbor->descr[0]) { > - p = getpeerbydesc(neighbor->descr); > - if (p == NULL) { > - control_result(c, > - CTL_RES_NOSUCHPEER); > - break; > - } > - ribreq->peerid = p->conf.id; > - } > - if ((ribreq->flags & > - (F_CTL_ADJ_OUT | F_CTL_ADJ_IN)) && !p) { > - /* > - * both in and out tables are only > - * meaningful if used on a single > - * peer. > - */ > - control_result(c, CTL_RES_NOSUCHPEER); > - break; > - } > - if ((imsg.hdr.type == IMSG_CTL_SHOW_RIB_PREFIX) > - && (ribreq->prefix.aid == AID_UNSPEC)) { > - /* malformed request, must specify af */ > - control_result(c, CTL_RES_PARSE_ERROR); > - break; > - } > - c->ibuf.pid = imsg.hdr.pid; > - c->terminate = 1; > - imsg_ctl_rde(imsg.hdr.type, imsg.hdr.pid, > - imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); > - } else > log_warnx("got IMSG_CTL_SHOW_RIB with " > "wrong length"); > + break; > + } > + > + ribreq = imsg.data; > + neighbor = &ribreq->neighbor; > + neighbor->descr[PEER_DESCR_LEN - 1] = 0; > + > + /* check if at least one neighbor exists */ > + for (p = peers; p != NULL; p = p->next) > + if (peer_matched(p, neighbor)) > + break; > + if (p == NULL) { > + control_result(c, CTL_RES_NOSUCHPEER); > + break; > + } > + > + if ((imsg.hdr.type == IMSG_CTL_SHOW_RIB_PREFIX) > + && (ribreq->prefix.aid == AID_UNSPEC)) { > + /* malformed request, must specify af */ > + control_result(c, CTL_RES_PARSE_ERROR); > + break; > + } > + > + c->ibuf.pid = imsg.hdr.pid; > + c->terminate = 1; > + > + imsg_ctl_rde(imsg.hdr.type, imsg.hdr.pid, > + imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); > break; > case IMSG_CTL_SHOW_NETWORK: > c->terminate = 1; > Index: bgpd/rde.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v > retrieving revision 1.459 > diff -u -p -r1.459 rde.c > --- bgpd/rde.c 18 Jan 2019 23:30:45 -0000 1.459 > +++ bgpd/rde.c 20 Jan 2019 06:40:21 -0000 > @@ -2251,12 +2251,29 @@ rde_dump_rib_as(struct prefix *p, struct > } > } > > +static int > +rde_dump_match_peer(struct ctl_neighbor *n, struct rde_peer *p) > +{ > + char *s; > + > + if (n && n->addr.aid) { > + if (memcmp(&p->conf.remote_addr, &n->addr, > + sizeof(p->conf.remote_addr))) > + return 0; > + } else if (n && n->descr[0]) { > + s = n->is_group ? p->conf.group : p->conf.descr; > + if (strcmp(s, n->descr)) > + return 0; > + } > + return 1; > +} > + > static void > rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req) > { > struct rde_aspath *asp; > > - if (req->peerid && req->peerid != prefix_peer(p)->conf.id) > + if (!rde_dump_match_peer(&req->neighbor, prefix_peer(p))) > return; > > asp = prefix_aspath(p); > Index: bgpd/session.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/session.c,v > retrieving revision 1.370 > diff -u -p -r1.370 session.c > --- bgpd/session.c 22 Oct 2018 07:46:55 -0000 1.370 > +++ bgpd/session.c 20 Jan 2019 06:39:01 -0000 > @@ -100,10 +100,10 @@ int session_link_state_is_up(int, int, i > > int la_cmp(struct listen_addr *, struct listen_addr *); > struct peer *getpeerbyip(struct sockaddr *); > +struct peer *getpeerbyid(u_int32_t); > void session_template_clone(struct peer *, struct sockaddr *, > u_int32_t, u_int32_t); > int session_match_mask(struct peer *, struct bgpd_addr *); > -struct peer *getpeerbyid(u_int32_t); > > struct bgpd_config *conf, *nconf; > struct bgpd_sysdep sysdep; > @@ -3114,6 +3114,36 @@ getpeerbyip(struct sockaddr *ip) > return (NULL); > } > > +struct peer * > +getpeerbyid(u_int32_t peerid) > +{ > + struct peer *p; > + > + /* we might want a more effective way to find peers by IP */ "by ID", the comment was wrong before. or remove it, i dont think it helps anyone. > + for (p = peers; p != NULL && > + p->conf.id != peerid; p = p->next) > + ; /* nothing */ > + > + return (p); > +} > + > +int > +peer_matched(struct peer *p, struct ctl_neighbor *n) > +{ > + char *s; > + > + if (n && n->addr.aid) { > + if (memcmp(&p->conf.remote_addr, &n->addr, > + sizeof(p->conf.remote_addr))) > + return 0; > + } else if (n && n->descr[0]) { > + s = n->is_group ? p->conf.group : p->conf.descr; > + if (strcmp(s, n->descr)) > + return 0; > + } > + return 1; > +} > + > void > session_template_clone(struct peer *p, struct sockaddr *ip, u_int32_t id, > u_int32_t as) > @@ -3170,19 +3200,6 @@ session_match_mask(struct peer *p, struc > return (0); > } > return (0); > -} > - > -struct peer * > -getpeerbyid(u_int32_t peerid) > -{ > - struct peer *p; > - > - /* we might want a more effective way to find peers by IP */ > - for (p = peers; p != NULL && > - p->conf.id != peerid; p = p->next) > - ; /* nothing */ > - > - return (p); > } > > void > Index: bgpd/session.h > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/session.h,v > retrieving revision 1.127 > diff -u -p -r1.127 session.h > --- bgpd/session.h 27 Dec 2018 20:23:24 -0000 1.127 > +++ bgpd/session.h 20 Jan 2019 06:04:02 -0000 > @@ -296,6 +296,7 @@ void bgp_fsm(struct peer *, enum sessi > int session_neighbor_rrefresh(struct peer *p); > struct peer *getpeerbyaddr(struct bgpd_addr *); > struct peer *getpeerbydesc(const char *); > +int peer_matched(struct peer *, struct ctl_neighbor *); > int imsg_ctl_parent(int, u_int32_t, pid_t, void *, u_int16_t); > int imsg_ctl_rde(int, pid_t, void *, u_int16_t); > void session_stop(struct peer *, u_int8_t); >