FreeBSD Bugzilla – Attachment 191795 Details for
Bug 223835
BGP session not established with md5 password via FRRouting
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch to net/openbgpd port
patch-bgpd_session.c (text/plain), 58.50 KB, created by
Andrey V. Elsukov
on 2018-03-25 05:05:33 UTC
(
hide
)
Description:
patch to net/openbgpd port
Filename:
MIME Type:
Creator:
Andrey V. Elsukov
Created:
2018-03-25 05:05:33 UTC
Size:
58.50 KB
patch
obsolete
>Index: bgpd/session.c >=================================================================== >RCS file: /home/cvs/private/hrs/openbgpd/bgpd/session.c,v >retrieving revision 1.1.1.8 >retrieving revision 1.13 >diff -u -p -r1.1.1.8 -r1.13 >--- bgpd/session.c 14 Feb 2010 20:19:57 -0000 1.1.1.8 >+++ bgpd/session.c 8 Dec 2012 20:17:59 -0000 1.13 >@@ -1,4 +1,4 @@ >-/* $OpenBSD: session.c,v 1.293 2009/06/07 05:56:24 eric Exp $ */ >+/* $OpenBSD: session.c,v 1.325 2012/09/18 09:45:50 claudio Exp $ */ > > /* > * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org> >@@ -21,18 +21,21 @@ > > #include <sys/mman.h> > #include <sys/socket.h> >+#include <sys/time.h> >+#include <sys/resource.h> > #include <sys/un.h> >+#include <sys/queue.h> > #include <net/if_types.h> > #include <netinet/in.h> > #include <netinet/in_systm.h> > #include <netinet/ip.h> > #include <netinet/tcp.h> >+#include <netinet/tcp_var.h> > #include <arpa/inet.h> > > #include <err.h> > #include <errno.h> > #include <fcntl.h> >-#include <limits.h> > #include <poll.h> > #include <pwd.h> > #include <signal.h> >@@ -50,7 +53,12 @@ > #define PFD_PIPE_ROUTE_CTL 2 > #define PFD_SOCK_CTL 3 > #define PFD_SOCK_RCTL 4 >-#define PFD_LISTENERS_START 5 >+#define PFD_SOCK_PFKEY 5 >+#define PFD_LISTENERS_START 6 >+ >+#if defined(__FreeBSD__) /* FreeBSD has no LINK_STATE_IS_UP macro. */ >+#define LINK_STATE_IS_UP(_s) ((_s) >= LINK_STATE_UP) >+#endif /* defined(__FreeBSD__) */ > > void session_sighdlr(int); > int setup_listeners(u_int *); >@@ -65,9 +73,9 @@ void session_accept(int); > int session_connect(struct peer *); > void session_tcp_established(struct peer *); > void session_capa_ann_none(struct peer *); >-int session_capa_add(struct peer *, struct buf *, u_int8_t, u_int8_t, >- u_int8_t *); >-int session_capa_add_mp(struct buf *, u_int16_t, u_int8_t); >+int session_capa_add(struct ibuf *, u_int8_t, u_int8_t); >+int session_capa_add_mp(struct ibuf *, u_int8_t); >+int session_capa_add_gr(struct peer *, struct ibuf *, u_int8_t); > struct bgp_msg *session_newmsg(enum msg_type, u_int16_t); > int session_sendmsg(struct bgp_msg *, struct peer *); > void session_open(struct peer *); >@@ -75,30 +83,34 @@ void session_keepalive(struct peer *); > void session_update(u_int32_t, void *, size_t); > void session_notification(struct peer *, u_int8_t, u_int8_t, void *, > ssize_t); >-void session_rrefresh(struct peer *, u_int16_t, u_int8_t); >+void session_rrefresh(struct peer *, u_int8_t); >+int session_graceful_restart(struct peer *); >+int session_graceful_is_restarting(struct peer *); >+int session_graceful_stop(struct peer *); > int session_dispatch_msg(struct pollfd *, struct peer *); >+int session_process_msg(struct peer *); > int parse_header(struct peer *, u_char *, u_int16_t *, u_int8_t *); > int parse_open(struct peer *); > int parse_update(struct peer *); > int parse_refresh(struct peer *); > int parse_notification(struct peer *); > int parse_capabilities(struct peer *, u_char *, u_int16_t, u_int32_t *); >+int capa_neg_calc(struct peer *); > void session_dispatch_imsg(struct imsgbuf *, int, u_int *); > void session_up(struct peer *); > void session_down(struct peer *); > void session_demote(struct peer *, int); > >-int la_cmp(struct listen_addr *, struct listen_addr *); >-struct peer *getpeerbyip(struct sockaddr *); >-int session_match_mask(struct peer *, struct sockaddr *); >-struct peer *getpeerbyid(u_int32_t); >-static struct sockaddr *addr2sa(struct bgpd_addr *, u_int16_t); >+int la_cmp(struct listen_addr *, struct listen_addr *); >+struct peer *getpeerbyip(struct sockaddr *); >+int session_match_mask(struct peer *, struct bgpd_addr *); >+struct peer *getpeerbyid(u_int32_t); > >-struct bgpd_config *conf, *nconf = NULL; >+struct bgpd_config *conf, *nconf; > struct bgpd_sysdep sysdep; >-struct peer *npeers; >-volatile sig_atomic_t session_quit = 0; >-int pending_reconf = 0; >+struct peer *peers, *npeers; >+volatile sig_atomic_t session_quit; >+int pending_reconf; > int csock = -1, rcsock = -1; > u_int peer_cnt; > struct imsgbuf *ibuf_rde; >@@ -106,6 +118,7 @@ struct imsgbuf *ibuf_rde_ctl; > struct imsgbuf *ibuf_main; > > struct mrt_head mrthead; >+time_t pauseaccept; > > void > session_sighdlr(int sig) >@@ -175,12 +206,10 @@ setup_listeners(u_int *la_cnt) > } > > pid_t >-session_main(struct bgpd_config *config, struct peer *cpeers, >- struct network_head *net_l, struct filter_head *rules, >- struct mrt_head *m_l, struct rib_names *rib_l, int pipe_m2s[2], >- int pipe_s2r[2], int pipe_m2r[2], int pipe_s2rctl[2]) >+session_main(int pipe_m2s[2], int pipe_s2r[2], int pipe_m2r[2], >+ int pipe_s2rctl[2]) > { >- int nfds, timeout; >+ int nfds, timeout, pfkeysock; > unsigned int i, j, idx_peers, idx_listeners, idx_mrts; > pid_t pid; > u_int pfd_elms = 0, peer_l_elms = 0, mrt_l_elms = 0; >@@ -189,19 +218,13 @@ session_main(struct bgpd_config *config, > u_int32_t ctl_queued; > struct passwd *pw; > struct peer *p, **peer_l = NULL, *last, *next; >- struct network *net; >- struct mrt *m, **mrt_l = NULL; >- struct filter_rule *r; >+ struct mrt *m, *xm, **mrt_l = NULL; > struct pollfd *pfd = NULL; > struct ctl_conn *ctl_conn; > struct listen_addr *la; >- struct rde_rib *rr; > void *newp; > short events; > >- conf = config; >- peers = cpeers; >- > switch (pid = fork()) { > case -1: > fatal("cannot fork"); >@@ -211,13 +234,6 @@ session_main(struct bgpd_config *config, > return (pid); > } > >- /* control socket is outside chroot */ >- if ((csock = control_init(0, conf->csock)) == -1) >- fatalx("control socket setup failed"); >- if (conf->rcsock != NULL && >- (rcsock = control_init(1, conf->rcsock)) == -1) >- fatalx("control socket setup failed"); >- > if ((pw = getpwnam(BGPD_USER)) == NULL) > fatal(NULL); > >@@ -228,29 +244,25 @@ session_main(struct bgpd_config *config, > > setproctitle("session engine"); > bgpd_process = PROC_SE; >- >- if (pfkey_init(&sysdep) == -1) >- fatalx("pfkey setup failed"); >+ pfkeysock = pfkey_init(&sysdep); > > if (setgroups(1, &pw->pw_gid) || > setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || > setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) > fatal("can't drop privileges"); > >- listener_cnt = 0; >- setup_listeners(&listener_cnt); >- > signal(SIGTERM, session_sighdlr); > signal(SIGINT, session_sighdlr); > signal(SIGPIPE, SIG_IGN); > signal(SIGHUP, SIG_IGN); >- log_info("session engine ready"); >+ signal(SIGALRM, SIG_IGN); >+ signal(SIGUSR1, SIG_IGN); >+ > close(pipe_m2s[0]); > close(pipe_s2r[1]); > close(pipe_s2rctl[1]); > close(pipe_m2r[0]); > close(pipe_m2r[1]); >- init_conf(conf); > if ((ibuf_rde = malloc(sizeof(struct imsgbuf))) == NULL || > (ibuf_rde_ctl = malloc(sizeof(struct imsgbuf))) == NULL || > (ibuf_main = malloc(sizeof(struct imsgbuf))) == NULL) >@@ -258,37 +270,21 @@ session_main(struct bgpd_config *config, > imsg_init(ibuf_rde, pipe_s2r[0]); > imsg_init(ibuf_rde_ctl, pipe_s2rctl[0]); > imsg_init(ibuf_main, pipe_m2s[1]); >+ > TAILQ_INIT(&ctl_conns); >- control_listen(csock); >- control_listen(rcsock); > LIST_INIT(&mrthead); >+ listener_cnt = 0; > peer_cnt = 0; > ctl_cnt = 0; > >- /* filter rules are not used in the SE */ >- while ((r = TAILQ_FIRST(rules)) != NULL) { >- TAILQ_REMOVE(rules, r, entry); >- free(r); >- } >- free(rules); >- >- /* network list is not used in the SE */ >- while ((net = TAILQ_FIRST(net_l)) != NULL) { >- TAILQ_REMOVE(net_l, net, entry); >- filterset_free(&net->net.attrset); >- free(net); >- } >+ if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL) >+ fatal(NULL); >+ if ((conf->listen_addrs = calloc(1, sizeof(struct listen_addrs))) == >+ NULL) >+ fatal(NULL); >+ TAILQ_INIT(conf->listen_addrs); > >- /* main mrt list is not used in the SE */ >- while ((m = LIST_FIRST(m_l)) != NULL) { >- LIST_REMOVE(m, entry); >- free(m); >- } >- /* rib names not used in the SE */ >- while ((rr = SIMPLEQ_FIRST(&ribnames))) { >- SIMPLEQ_REMOVE_HEAD(&ribnames, entry); >- free(rr); >- } >+ log_info("session engine ready"); > > while (session_quit == 0) { > /* check for peers to be initialized or deleted */ >@@ -308,8 +304,9 @@ session_main(struct bgpd_config *config, > > /* reinit due? */ > if (p->conf.reconf_action == RECONF_REINIT) { >- bgp_fsm(p, EVNT_STOP); >- timer_set(p, Timer_IdleHold, 0); >+ session_stop(p, ERR_CEASE_ADMIN_RESET); >+ if (!p->conf.down) >+ timer_set(p, Timer_IdleHold, 0); > } > > /* deletion due? */ >@@ -317,7 +314,7 @@ session_main(struct bgpd_config *config, > if (p->demoted) > session_demote(p, -1); > p->conf.demote_group[0] = 0; >- bgp_fsm(p, EVNT_STOP); >+ session_stop(p, ERR_CEASE_PEER_UNCONF); > log_peer_warnx(&p->conf, "removed"); > if (last != NULL) > last->next = next; >@@ -346,9 +343,17 @@ session_main(struct bgpd_config *config, > } > > mrt_cnt = 0; >- LIST_FOREACH(m, &mrthead, entry) >+ for (m = LIST_FIRST(&mrthead); m != NULL; m = xm) { >+ xm = LIST_NEXT(m, entry); >+ if (m->state == MRT_STATE_REMOVE) { >+ mrt_clean(m); >+ LIST_REMOVE(m, entry); >+ free(m); >+ continue; >+ } > if (m->wbuf.queued) > mrt_cnt++; >+ } > > if (mrt_cnt > mrt_l_elms) { > if ((newp = realloc(mrt_l, sizeof(struct mrt *) * >@@ -394,18 +399,31 @@ session_main(struct bgpd_config *config, > if (ctl_queued < SESSION_CTL_QUEUE_MAX) > /* > * Do not act as unlimited buffer. Don't read in more >- * messages if the ctl sockets are getting full. >+ * messages if the ctl sockets are getting full. > */ > pfd[PFD_PIPE_ROUTE_CTL].events = POLLIN; >- pfd[PFD_SOCK_CTL].fd = csock; >- pfd[PFD_SOCK_CTL].events = POLLIN; >- pfd[PFD_SOCK_RCTL].fd = rcsock; >- pfd[PFD_SOCK_RCTL].events = POLLIN; >- >+ if (pauseaccept == 0) { >+ pfd[PFD_SOCK_CTL].fd = csock; >+ pfd[PFD_SOCK_CTL].events = POLLIN; >+ pfd[PFD_SOCK_RCTL].fd = rcsock; >+ pfd[PFD_SOCK_RCTL].events = POLLIN; >+ } else { >+ pfd[PFD_SOCK_CTL].fd = -1; >+ pfd[PFD_SOCK_RCTL].fd = -1; >+ } >+ pfd[PFD_SOCK_PFKEY].fd = pfkeysock; >+#if !defined(__FreeBSD__) >+ pfd[PFD_SOCK_PFKEY].events = POLLIN; >+#else >+ pfd[PFD_SOCK_PFKEY].events = 0; >+#endif > i = PFD_LISTENERS_START; > TAILQ_FOREACH(la, conf->listen_addrs, entry) { >- pfd[i].fd = la->fd; >- pfd[i].events = POLLIN; >+ if (pauseaccept == 0) { >+ pfd[i].fd = la->fd; >+ pfd[i].events = POLLIN; >+ } else >+ pfd[i].fd = -1; > i++; > } > idx_listeners = i; >@@ -450,6 +468,10 @@ session_main(struct bgpd_config *config, > p->state == STATE_ESTABLISHED) > session_demote(p, -1); > break; >+ case Timer_RestartTimeout: >+ timer_stop(p, Timer_RestartTimeout); >+ session_graceful_stop(p); >+ break; > default: > fatalx("King Bula lost in time"); > } >@@ -462,6 +484,9 @@ session_main(struct bgpd_config *config, > events = POLLIN; > if (p->wbuf.queued > 0 || p->state == STATE_CONNECT) > events |= POLLOUT; >+ /* is there still work to do? */ >+ if (p->rbuf && p->rbuf->wpos) >+ timeout = 0; > > /* poll events */ > if (p->fd != -1 && events != 0) { >@@ -492,12 +517,21 @@ session_main(struct bgpd_config *config, > i++; > } > >+ if (pauseaccept && timeout > 1) >+ timeout = 1; > if (timeout < 0) > timeout = 0; > if ((nfds = poll(pfd, i, timeout * 1000)) == -1) > if (errno != EINTR) > fatal("poll error"); > >+ /* >+ * If we previously saw fd exhaustion, we stop accept() >+ * for 1 second to throttle the accept() loop. >+ */ >+ if (pauseaccept && getmonotime() > pauseaccept + 1) >+ pauseaccept = 0; >+ > if (nfds > 0 && pfd[PFD_PIPE_MAIN].revents & POLLOUT) > if (msgbuf_write(&ibuf_main->w) < 0) > fatal("pipe write error"); >@@ -534,6 +568,14 @@ session_main(struct bgpd_config *config, > ctl_cnt += control_accept(rcsock, 1); > } > >+ if (nfds > 0 && pfd[PFD_SOCK_PFKEY].revents & POLLIN) { >+ nfds--; >+ if (pfkey_read(pfkeysock, NULL) == -1) { >+ log_warnx("pfkey_read failed, exiting..."); >+ session_quit = 1; >+ } >+ } >+ > for (j = PFD_LISTENERS_START; nfds > 0 && j < idx_listeners; > j++) > if (pfd[j].revents & POLLIN) { >@@ -545,6 +587,10 @@ session_main(struct bgpd_config *config, > nfds -= session_dispatch_msg(&pfd[j], > peer_l[j - idx_listeners]); > >+ for (p = peers; p != NULL; p = p->next) >+ if (p->rbuf && p->rbuf->wpos) >+ session_process_msg(p); >+ > for (; nfds > 0 && j < idx_mrts; j++) > if (pfd[j].revents & POLLOUT) { > nfds--; >@@ -557,7 +603,7 @@ session_main(struct bgpd_config *config, > > while ((p = peers) != NULL) { > peers = p->next; >- bgp_fsm(p, EVNT_STOP); >+ session_stop(p, ERR_CEASE_ADMIN_DOWN); > pfkey_remove(p); > free(p); > } >@@ -643,10 +689,9 @@ bgp_fsm(struct peer *peer, enum session_ > timer_stop(peer, Timer_IdleHold); > > /* allocate read buffer */ >- peer->rbuf = calloc(1, sizeof(struct buf_read)); >+ peer->rbuf = calloc(1, sizeof(struct ibuf_read)); > if (peer->rbuf == NULL) > fatal(NULL); >- peer->rbuf->wpos = 0; > > /* init write buffer */ > msgbuf_init(&peer->wbuf); >@@ -746,7 +791,6 @@ bgp_fsm(struct peer *peer, enum session_ > /* ignore */ > break; > case EVNT_STOP: >- session_notification(peer, ERR_CEASE, 0, NULL, 0); > change_state(peer, STATE_IDLE, event); > break; > case EVNT_CON_CLOSED: >@@ -780,7 +824,8 @@ bgp_fsm(struct peer *peer, enum session_ > change_state(peer, STATE_IDLE, event); > break; > default: >- session_notification(peer, ERR_FSM, 0, NULL, 0); >+ session_notification(peer, >+ ERR_FSM, ERR_FSM_UNEX_OPENSENT, NULL, 0); > change_state(peer, STATE_IDLE, event); > break; > } >@@ -791,7 +836,6 @@ bgp_fsm(struct peer *peer, enum session_ > /* ignore */ > break; > case EVNT_STOP: >- session_notification(peer, ERR_CEASE, 0, NULL, 0); > change_state(peer, STATE_IDLE, event); > break; > case EVNT_CON_CLOSED: >@@ -815,7 +859,8 @@ bgp_fsm(struct peer *peer, enum session_ > change_state(peer, STATE_IDLE, event); > break; > default: >- session_notification(peer, ERR_FSM, 0, NULL, 0); >+ session_notification(peer, >+ ERR_FSM, ERR_FSM_UNEX_OPENCONFIRM, NULL, 0); > change_state(peer, STATE_IDLE, event); > break; > } >@@ -826,7 +871,6 @@ bgp_fsm(struct peer *peer, enum session_ > /* ignore */ > break; > case EVNT_STOP: >- session_notification(peer, ERR_CEASE, 0, NULL, 0); > change_state(peer, STATE_IDLE, event); > break; > case EVNT_CON_CLOSED: >@@ -856,7 +900,8 @@ bgp_fsm(struct peer *peer, enum session_ > change_state(peer, STATE_IDLE, event); > break; > default: >- session_notification(peer, ERR_FSM, 0, NULL, 0); >+ session_notification(peer, >+ ERR_FSM, ERR_FSM_UNEX_ESTABLISHED, NULL, 0); > change_state(peer, STATE_IDLE, event); > break; > } >@@ -885,9 +930,10 @@ start_timer_keepalive(struct peer *peer) > void > session_close_connection(struct peer *peer) > { >- if (peer->fd != -1) >+ if (peer->fd != -1) { > close(peer->fd); >- >+ pauseaccept = 0; >+ } > peer->fd = peer->wbuf.fd = -1; > } > >@@ -923,20 +969,31 @@ change_state(struct peer *peer, enum ses > timer_stop(peer, Timer_ConnectRetry); > timer_stop(peer, Timer_Keepalive); > timer_stop(peer, Timer_Hold); >+ timer_stop(peer, Timer_IdleHold); > timer_stop(peer, Timer_IdleHoldReset); > session_close_connection(peer); > msgbuf_clear(&peer->wbuf); > free(peer->rbuf); > peer->rbuf = NULL; > bzero(&peer->capa.peer, sizeof(peer->capa.peer)); >- if (peer->state == STATE_ESTABLISHED) >- session_down(peer); >+ > if (event != EVNT_STOP) { > timer_set(peer, Timer_IdleHold, peer->IdleHoldTime); > if (event != EVNT_NONE && > peer->IdleHoldTime < MAX_IDLE_HOLD/2) > peer->IdleHoldTime *= 2; > } >+ if (peer->state == STATE_ESTABLISHED) { >+ if (peer->capa.neg.grestart.restart == 2 && >+ (event == EVNT_CON_CLOSED || >+ event == EVNT_CON_FATAL)) { >+ /* don't punish graceful restart */ >+ timer_set(peer, Timer_IdleHold, 0); >+ peer->IdleHoldTime /= 2; >+ session_graceful_restart(peer); >+ } else >+ session_down(peer); >+ } > if (peer->state == STATE_NONE || > peer->state == STATE_ESTABLISHED) { > /* initialize capability negotiation structures */ >@@ -947,6 +1004,20 @@ change_state(struct peer *peer, enum ses > } > break; > case STATE_CONNECT: >+ if (peer->state == STATE_ESTABLISHED && >+ peer->capa.neg.grestart.restart == 2) { >+ /* do the graceful restart dance */ >+ session_graceful_restart(peer); >+ peer->holdtime = INTERVAL_HOLD_INITIAL; >+ timer_stop(peer, Timer_ConnectRetry); >+ timer_stop(peer, Timer_Keepalive); >+ timer_stop(peer, Timer_Hold); >+ timer_stop(peer, Timer_IdleHold); >+ timer_stop(peer, Timer_IdleHoldReset); >+ session_close_connection(peer); >+ msgbuf_clear(&peer->wbuf); >+ bzero(&peer->capa.peer, sizeof(peer->capa.peer)); >+ } > break; > case STATE_ACTIVE: > break; >@@ -990,7 +1061,10 @@ session_accept(int listenfd) > len = sizeof(cliaddr); > if ((connfd = accept(listenfd, > (struct sockaddr *)&cliaddr, &len)) == -1) { >- if (errno == EWOULDBLOCK || errno == EINTR) >+ if (errno == ENFILE || errno == EMFILE) { >+ pauseaccept = getmonotime(); >+ return; >+ } else if (errno == EWOULDBLOCK || errno == EINTR) > return; > else > log_warn("accept"); >@@ -1017,6 +1091,7 @@ session_accept(int listenfd) > } > } > >+open: > if (p->conf.auth.method != AUTH_NONE && sysdep.no_pfkey) { > log_peer_warnx(&p->conf, > "ipsec or md5sig configured but not available"); >@@ -1049,6 +1124,13 @@ session_accept(int listenfd) > } > session_socket_blockmode(connfd, BM_NONBLOCK); > bgp_fsm(p, EVNT_CON_OPEN); >+ return; >+ } else if (p != NULL && p->state == STATE_ESTABLISHED && >+ p->capa.neg.grestart.restart == 2) { >+ /* first do the graceful restart dance */ >+ change_state(p, STATE_CONNECT, EVNT_CON_CLOSED); >+ /* then do part of the open dance */ >+ goto open; > } else { > log_conn_attempt(p, (struct sockaddr *)&cliaddr); > close(connfd); >@@ -1069,7 +1151,7 @@ session_connect(struct peer *peer) > if (peer->fd != -1) > return (-1); > >- if ((peer->fd = socket(peer->conf.remote_addr.af, SOCK_STREAM, >+ if ((peer->fd = socket(aid2af(peer->conf.remote_addr.aid), SOCK_STREAM, > IPPROTO_TCP)) == -1) { > log_peer_warn(&peer->conf, "session_connect socket"); > bgp_fsm(peer, EVNT_CON_OPENFAIL); >@@ -1100,8 +1182,7 @@ session_connect(struct peer *peer) > peer->wbuf.fd = peer->fd; > > /* if update source is set we need to bind() */ >- if (peer->conf.local_addr.af) { >- sa = addr2sa(&peer->conf.local_addr, 0); >+ if ((sa = addr2sa(&peer->conf.local_addr, 0)) != NULL) { > if (bind(peer->fd, sa, sa->sa_len) == -1) { > log_peer_warn(&peer->conf, "session_connect bind"); > bgp_fsm(peer, EVNT_CON_OPENFAIL); >@@ -1139,42 +1220,50 @@ session_setup_socket(struct peer *p) > int nodelay = 1; > int bsize; > >- if (p->conf.ebgp && p->conf.remote_addr.af == AF_INET) { >- /* set TTL to foreign router's distance - 1=direct n=multihop >- with ttlsec, we always use 255 */ >- if (p->conf.ttlsec) { >- ttl = 256 - p->conf.distance; >- if (setsockopt(p->fd, IPPROTO_IP, IP_MINTTL, &ttl, >+ switch (p->conf.remote_addr.aid) { >+ case AID_INET: >+ /* set precedence, see RFC 1771 appendix 5 */ >+ if (setsockopt(p->fd, IPPROTO_IP, IP_TOS, &pre, sizeof(pre)) == >+ -1) { >+ log_peer_warn(&p->conf, >+ "session_setup_socket setsockopt TOS"); >+ return (-1); >+ } >+ >+ if (p->conf.ebgp) { >+ /* set TTL to foreign router's distance >+ 1=direct n=multihop with ttlsec, we always use 255 */ >+ if (p->conf.ttlsec) { >+ ttl = 256 - p->conf.distance; >+ if (setsockopt(p->fd, IPPROTO_IP, IP_MINTTL, >+ &ttl, sizeof(ttl)) == -1) { >+ log_peer_warn(&p->conf, >+ "session_setup_socket: " >+ "setsockopt MINTTL"); >+ return (-1); >+ } >+ ttl = 255; >+ } >+ >+ if (setsockopt(p->fd, IPPROTO_IP, IP_TTL, &ttl, > sizeof(ttl)) == -1) { > log_peer_warn(&p->conf, >- "session_setup_socket setsockopt MINTTL"); >+ "session_setup_socket setsockopt TTL"); > return (-1); > } >- ttl = 255; >- } >- >- if (setsockopt(p->fd, IPPROTO_IP, IP_TTL, &ttl, >- sizeof(ttl)) == -1) { >- log_peer_warn(&p->conf, >- "session_setup_socket setsockopt TTL"); >- return (-1); > } >- } >- >- if (p->conf.ebgp && p->conf.remote_addr.af == AF_INET6) >- /* set hoplimit to foreign router's distance */ >- if (setsockopt(p->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, >- sizeof(ttl)) == -1) { >- log_peer_warn(&p->conf, >- "session_setup_socket setsockopt hoplimit"); >- return (-1); >+ break; >+ case AID_INET6: >+ if (p->conf.ebgp) { >+ /* set hoplimit to foreign router's distance */ >+ if (setsockopt(p->fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, >+ &ttl, sizeof(ttl)) == -1) { >+ log_peer_warn(&p->conf, >+ "session_setup_socket setsockopt hoplimit"); >+ return (-1); >+ } > } >- >- /* if ttlsec is in use, set minttl */ >- if (p->conf.ttlsec) { >- ttl = 256 - p->conf.distance; >- setsockopt(p->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)); >- >+ break; > } > > /* set TCP_NODELAY */ >@@ -1185,24 +1274,18 @@ session_setup_socket(struct peer *p) > return (-1); > } > >- /* set precedence, see RFC 1771 appendix 5 */ >- if (p->conf.remote_addr.af == AF_INET && >- setsockopt(p->fd, IPPROTO_IP, IP_TOS, &pre, sizeof(pre)) == -1) { >- log_peer_warn(&p->conf, >- "session_setup_socket setsockopt TOS"); >- return (-1); >- } >- > /* only increase bufsize (and thus window) if md5 or ipsec is in use */ > if (p->conf.auth.method != AUTH_NONE) { > /* try to increase bufsize. no biggie if it fails */ > bsize = 65535; >- while (setsockopt(p->fd, SOL_SOCKET, SO_RCVBUF, &bsize, >- sizeof(bsize)) == -1) >+ while (bsize > 8192 && >+ setsockopt(p->fd, SOL_SOCKET, SO_RCVBUF, &bsize, >+ sizeof(bsize)) == -1 && errno != EINVAL) > bsize /= 2; > bsize = 65535; >- while (setsockopt(p->fd, SOL_SOCKET, SO_SNDBUF, &bsize, >- sizeof(bsize)) == -1) >+ while (bsize > 8192 && >+ setsockopt(p->fd, SOL_SOCKET, SO_SNDBUF, &bsize, >+ sizeof(bsize)) == -1 && errno != EINVAL) > bsize /= 2; > } > >@@ -1244,40 +1327,56 @@ session_tcp_established(struct peer *pee > void > session_capa_ann_none(struct peer *peer) > { >- peer->capa.ann.mp_v4 = SAFI_NONE; >- peer->capa.ann.mp_v4 = SAFI_NONE; >- peer->capa.ann.refresh = 0; >- peer->capa.ann.restart = 0; >- peer->capa.ann.as4byte = 0; >+ bzero(&peer->capa.ann, sizeof(peer->capa.ann)); > } > > int >-session_capa_add(struct peer *p, struct buf *opb, u_int8_t capa_code, >- u_int8_t capa_len, u_int8_t *optparamlen) >-{ >- u_int8_t op_type, op_len, tot_len, errs = 0; >- >- op_type = OPT_PARAM_CAPABILITIES; >- op_len = sizeof(capa_code) + sizeof(capa_len) + capa_len; >- tot_len = sizeof(op_type) + sizeof(op_len) + op_len; >- errs += buf_add(opb, &op_type, sizeof(op_type)); >- errs += buf_add(opb, &op_len, sizeof(op_len)); >- errs += buf_add(opb, &capa_code, sizeof(capa_code)); >- errs += buf_add(opb, &capa_len, sizeof(capa_len)); >- *optparamlen += tot_len; >+session_capa_add(struct ibuf *opb, u_int8_t capa_code, u_int8_t capa_len) >+{ >+ int errs = 0; >+ >+ errs += ibuf_add(opb, &capa_code, sizeof(capa_code)); >+ errs += ibuf_add(opb, &capa_len, sizeof(capa_len)); > return (errs); > } > > int >-session_capa_add_mp(struct buf *buf, u_int16_t afi, u_int8_t safi) >+session_capa_add_mp(struct ibuf *buf, u_int8_t aid) > { >- u_int8_t pad = 0; >+ u_int8_t safi, pad = 0; >+ u_int16_t afi; > int errs = 0; > >+ if (aid2afi(aid, &afi, &safi) == -1) >+ fatalx("session_capa_add_mp: bad afi/safi pair"); >+ afi = htons(afi); >+ errs += ibuf_add(buf, &afi, sizeof(afi)); >+ errs += ibuf_add(buf, &pad, sizeof(pad)); >+ errs += ibuf_add(buf, &safi, sizeof(safi)); >+ >+ return (errs); >+} >+ >+int >+session_capa_add_gr(struct peer *p, struct ibuf *b, u_int8_t aid) >+{ >+ u_int errs = 0; >+ u_int16_t afi; >+ u_int8_t flags, safi; >+ >+ if (aid2afi(aid, &afi, &safi)) { >+ log_warn("session_capa_add_gr: bad AID"); >+ return (1); >+ } >+ if (p->capa.neg.grestart.flags[aid] & CAPA_GR_RESTARTING) >+ flags = CAPA_GR_F_FLAG; >+ else >+ flags = 0; >+ > afi = htons(afi); >- errs += buf_add(buf, &afi, sizeof(afi)); >- errs += buf_add(buf, &pad, sizeof(pad)); >- errs += buf_add(buf, &safi, sizeof(safi)); >+ errs += ibuf_add(b, &afi, sizeof(afi)); >+ errs += ibuf_add(b, &safi, sizeof(safi)); >+ errs += ibuf_add(b, &flags, sizeof(flags)); > > return (errs); > } >@@ -1287,23 +1386,22 @@ session_newmsg(enum msg_type msgtype, u_ > { > struct bgp_msg *msg; > struct msg_header hdr; >- struct buf *buf; >+ struct ibuf *buf; > int errs = 0; > > memset(&hdr.marker, 0xff, sizeof(hdr.marker)); > hdr.len = htons(len); > hdr.type = msgtype; > >- if ((buf = buf_open(len)) == NULL) >+ if ((buf = ibuf_open(len)) == NULL) > return (NULL); > >- errs += buf_add(buf, &hdr.marker, sizeof(hdr.marker)); >- errs += buf_add(buf, &hdr.len, sizeof(hdr.len)); >- errs += buf_add(buf, &hdr.type, sizeof(hdr.type)); >- >- if (errs > 0 || >- (msg = calloc(1, sizeof(*msg))) == NULL) { >- buf_free(buf); >+ errs += ibuf_add(buf, &hdr.marker, sizeof(hdr.marker)); >+ errs += ibuf_add(buf, &hdr.len, sizeof(hdr.len)); >+ errs += ibuf_add(buf, &hdr.type, sizeof(hdr.type)); >+ >+ if (errs || (msg = calloc(1, sizeof(*msg))) == NULL) { >+ ibuf_free(buf); > return (NULL); > } > >@@ -1329,7 +1427,7 @@ session_sendmsg(struct bgp_msg *msg, str > mrt_dump_bgp_msg(mrt, msg->buf->buf, msg->len, p); > } > >- buf_close(&p->wbuf, msg->buf); >+ ibuf_close(&p->wbuf, msg->buf); > free(msg); > return (0); > } >@@ -1338,40 +1436,70 @@ void > session_open(struct peer *p) > { > struct bgp_msg *buf; >- struct buf *opb; >+ struct ibuf *opb; > struct msg_open msg; > u_int16_t len; >- u_int8_t optparamlen = 0; >- u_int errs = 0; >+ u_int8_t i, op_type, optparamlen = 0; >+ int errs = 0; >+ int mpcapa = 0; > > >- if ((opb = buf_dynamic(0, MAX_PKTSIZE - MSGSIZE_OPEN_MIN)) == NULL) { >+ if ((opb = ibuf_dynamic(0, UCHAR_MAX - sizeof(op_type) - >+ sizeof(optparamlen))) == NULL) { > bgp_fsm(p, EVNT_CON_FATAL); > return; > } > > /* multiprotocol extensions, RFC 4760 */ >- if (p->capa.ann.mp_v4) { /* 4 bytes data */ >- errs += session_capa_add(p, opb, CAPA_MP, 4, &optparamlen); >- errs += session_capa_add_mp(opb, AFI_IPv4, p->capa.ann.mp_v4); >- } >- if (p->capa.ann.mp_v6) { /* 4 bytes data */ >- errs += session_capa_add(p, opb, CAPA_MP, 4, &optparamlen); >- errs += session_capa_add_mp(opb, AFI_IPv6, p->capa.ann.mp_v6); >- } >+ for (i = 0; i < AID_MAX; i++) >+ if (p->capa.ann.mp[i]) { /* 4 bytes data */ >+ errs += session_capa_add(opb, CAPA_MP, 4); >+ errs += session_capa_add_mp(opb, i); >+ mpcapa++; >+ } > > /* route refresh, RFC 2918 */ > if (p->capa.ann.refresh) /* no data */ >- errs += session_capa_add(p, opb, CAPA_REFRESH, 0, &optparamlen); >+ errs += session_capa_add(opb, CAPA_REFRESH, 0); > >- /* End-of-RIB marker, RFC 4724 */ >- if (p->capa.ann.restart) { /* 2 bytes data */ >- u_char c[2]; >- >- bzero(&c, 2); >- c[0] = 0x80; /* we're always restarting */ >- errs += session_capa_add(p, opb, CAPA_RESTART, 2, &optparamlen); >- errs += buf_add(opb, &c, 2); >+ /* graceful restart and End-of-RIB marker, RFC 4724 */ >+ if (p->capa.ann.grestart.restart) { >+ int rst = 0; >+ u_int16_t hdr; >+ u_int8_t grlen; >+ >+ if (mpcapa) { >+ grlen = 2 + 4 * mpcapa; >+ for (i = 0; i < AID_MAX; i++) { >+ if (p->capa.neg.grestart.flags[i] & >+ CAPA_GR_RESTARTING) >+ rst++; >+ } >+ } else { /* AID_INET */ >+ grlen = 2 + 4; >+ if (p->capa.neg.grestart.flags[AID_INET] & >+ CAPA_GR_RESTARTING) >+ rst++; >+ } >+ >+ hdr = conf->holdtime; /* default timeout */ >+ /* if client does graceful restart don't set R flag */ >+ if (!rst) >+ hdr |= CAPA_GR_R_FLAG; >+ hdr = htons(hdr); >+ >+ errs += session_capa_add(opb, CAPA_RESTART, grlen); >+ errs += ibuf_add(opb, &hdr, sizeof(hdr)); >+ >+ if (mpcapa) { >+ for (i = 0; i < AID_MAX; i++) { >+ if (p->capa.ann.mp[i]) { >+ errs += session_capa_add_gr(p, opb, i); >+ } >+ } >+ } else { /* AID_INET */ >+ errs += session_capa_add_gr(p, opb, AID_INET); >+ } > } > > /* 4-bytes AS numbers, draft-ietf-idr-as4bytes-13 */ >@@ -1379,13 +1507,17 @@ session_open(struct peer *p) > u_int32_t nas; > > nas = htonl(conf->as); >- errs += session_capa_add(p, opb, CAPA_AS4BYTE, 4, &optparamlen); >- errs += buf_add(opb, &nas, 4); >+ errs += session_capa_add(opb, CAPA_AS4BYTE, sizeof(nas)); >+ errs += ibuf_add(opb, &nas, sizeof(nas)); > } > >+ if (ibuf_size(opb)) >+ optparamlen = ibuf_size(opb) + sizeof(op_type) + >+ sizeof(optparamlen); >+ > len = MSGSIZE_OPEN_MIN + optparamlen; > if (errs || (buf = session_newmsg(OPEN, len)) == NULL) { >- buf_free(opb); >+ ibuf_free(opb); > bgp_fsm(p, EVNT_CON_FATAL); > return; > } >@@ -1399,19 +1531,24 @@ session_open(struct peer *p) > msg.bgpid = conf->bgpid; /* is already in network byte order */ > msg.optparamlen = optparamlen; > >- errs += buf_add(buf->buf, &msg.version, sizeof(msg.version)); >- errs += buf_add(buf->buf, &msg.myas, sizeof(msg.myas)); >- errs += buf_add(buf->buf, &msg.holdtime, sizeof(msg.holdtime)); >- errs += buf_add(buf->buf, &msg.bgpid, sizeof(msg.bgpid)); >- errs += buf_add(buf->buf, &msg.optparamlen, sizeof(msg.optparamlen)); >- >- if (optparamlen) >- errs += buf_add(buf->buf, opb->buf, optparamlen); >+ errs += ibuf_add(buf->buf, &msg.version, sizeof(msg.version)); >+ errs += ibuf_add(buf->buf, &msg.myas, sizeof(msg.myas)); >+ errs += ibuf_add(buf->buf, &msg.holdtime, sizeof(msg.holdtime)); >+ errs += ibuf_add(buf->buf, &msg.bgpid, sizeof(msg.bgpid)); >+ errs += ibuf_add(buf->buf, &msg.optparamlen, sizeof(msg.optparamlen)); >+ >+ if (optparamlen) { >+ op_type = OPT_PARAM_CAPABILITIES; >+ optparamlen = ibuf_size(opb); >+ errs += ibuf_add(buf->buf, &op_type, sizeof(op_type)); >+ errs += ibuf_add(buf->buf, &optparamlen, sizeof(optparamlen)); >+ errs += ibuf_add(buf->buf, opb->buf, ibuf_size(opb)); >+ } > >- buf_free(opb); >+ ibuf_free(opb); > >- if (errs > 0) { >- buf_free(buf->buf); >+ if (errs) { >+ ibuf_free(buf->buf); > free(buf); > bgp_fsm(p, EVNT_CON_FATAL); > return; >@@ -1459,8 +1596,8 @@ session_update(u_int32_t peerid, void *d > return; > } > >- if (buf_add(buf->buf, data, datalen)) { >- buf_free(buf->buf); >+ if (ibuf_add(buf->buf, data, datalen)) { >+ ibuf_free(buf->buf); > free(buf); > bgp_fsm(p, EVNT_CON_FATAL); > return; >@@ -1480,29 +1617,27 @@ session_notification(struct peer *p, u_i > void *data, ssize_t datalen) > { > struct bgp_msg *buf; >- u_int errs = 0; >- u_int8_t null8 = 0; >+ int errs = 0; > > if (p->stats.last_sent_errcode) /* some notification already sent */ > return; > >+ log_notification(p, errcode, subcode, data, datalen, "sending"); >+ > if ((buf = session_newmsg(NOTIFICATION, > MSGSIZE_NOTIFICATION_MIN + datalen)) == NULL) { > bgp_fsm(p, EVNT_CON_FATAL); > return; > } > >- errs += buf_add(buf->buf, &errcode, sizeof(errcode)); >- if (errcode == ERR_CEASE) >- errs += buf_add(buf->buf, &null8, sizeof(null8)); >- else >- errs += buf_add(buf->buf, &subcode, sizeof(subcode)); >+ errs += ibuf_add(buf->buf, &errcode, sizeof(errcode)); >+ errs += ibuf_add(buf->buf, &subcode, sizeof(subcode)); > > if (datalen > 0) >- errs += buf_add(buf->buf, data, datalen); >+ errs += ibuf_add(buf->buf, data, datalen); > >- if (errs > 0) { >- buf_free(buf->buf); >+ if (errs) { >+ ibuf_free(buf->buf); > free(buf); > bgp_fsm(p, EVNT_CON_FATAL); > return; >@@ -1521,23 +1656,29 @@ session_notification(struct peer *p, u_i > int > session_neighbor_rrefresh(struct peer *p) > { >+ u_int8_t i; >+ > if (!p->capa.peer.refresh) > return (-1); > >- if (p->capa.peer.mp_v4 != SAFI_NONE) >- session_rrefresh(p, AFI_IPv4, p->capa.peer.mp_v4); >- if (p->capa.peer.mp_v6 != SAFI_NONE) >- session_rrefresh(p, AFI_IPv6, p->capa.peer.mp_v6); >+ for (i = 0; i < AID_MAX; i++) { >+ if (p->capa.peer.mp[i] != 0) >+ session_rrefresh(p, i); >+ } > > return (0); > } > > void >-session_rrefresh(struct peer *p, u_int16_t afi, u_int8_t safi) >+session_rrefresh(struct peer *p, u_int8_t aid) > { > struct bgp_msg *buf; > int errs = 0; >- u_int8_t null8 = 0; >+ u_int16_t afi; >+ u_int8_t safi, null8 = 0; >+ >+ if (aid2afi(aid, &afi, &safi) == -1) >+ fatalx("session_rrefresh: bad afi/safi pair"); > > if ((buf = session_newmsg(RREFRESH, MSGSIZE_RREFRESH)) == NULL) { > bgp_fsm(p, EVNT_CON_FATAL); >@@ -1545,12 +1686,12 @@ session_rrefresh(struct peer *p, u_int16 > } > > afi = htons(afi); >- errs += buf_add(buf->buf, &afi, sizeof(afi)); >- errs += buf_add(buf->buf, &null8, sizeof(null8)); >- errs += buf_add(buf->buf, &safi, sizeof(safi)); >+ errs += ibuf_add(buf->buf, &afi, sizeof(afi)); >+ errs += ibuf_add(buf->buf, &null8, sizeof(null8)); >+ errs += ibuf_add(buf->buf, &safi, sizeof(safi)); > >- if (errs > 0) { >- buf_free(buf->buf); >+ if (errs) { >+ ibuf_free(buf->buf); > free(buf); > bgp_fsm(p, EVNT_CON_FATAL); > return; >@@ -1565,13 +1706,74 @@ session_rrefresh(struct peer *p, u_int16 > } > > int >+session_graceful_restart(struct peer *p) >+{ >+ u_int8_t i; >+ >+ timer_set(p, Timer_RestartTimeout, p->capa.neg.grestart.timeout); >+ >+ for (i = 0; i < AID_MAX; i++) { >+ if (p->capa.neg.grestart.flags[i] & CAPA_GR_PRESENT) { >+ if (imsg_compose(ibuf_rde, IMSG_SESSION_STALE, >+ p->conf.id, 0, -1, &i, sizeof(i)) == -1) >+ return (-1); >+ log_peer_warnx(&p->conf, >+ "graceful restart of %s, keeping routes", >+ aid2str(i)); >+ p->capa.neg.grestart.flags[i] |= CAPA_GR_RESTARTING; >+ } else if (p->capa.neg.mp[i]) { >+ if (imsg_compose(ibuf_rde, IMSG_SESSION_FLUSH, >+ p->conf.id, 0, -1, &i, sizeof(i)) == -1) >+ return (-1); >+ log_peer_warnx(&p->conf, >+ "graceful restart of %s, flushing routes", >+ aid2str(i)); >+ } >+ } >+ return (0); >+} >+ >+int >+session_graceful_is_restarting(struct peer *p) >+{ >+ u_int8_t i; >+ >+ for (i = 0; i < AID_MAX; i++) >+ if (p->capa.neg.grestart.flags[i] & CAPA_GR_RESTARTING) >+ return (1); >+ return (0); >+} >+ >+int >+session_graceful_stop(struct peer *p) >+{ >+ u_int8_t i; >+ >+ for (i = 0; i < AID_MAX; i++) { >+ /* >+ * Only flush if the peer is restarting and the peer indicated >+ * it hold the forwarding state. In all other cases the >+ * session was already flushed when the session came up. >+ */ >+ if (p->capa.neg.grestart.flags[i] & CAPA_GR_RESTARTING && >+ p->capa.neg.grestart.flags[i] & CAPA_GR_FORWARD) { >+ log_peer_warnx(&p->conf, "graceful restart of %s, " >+ "time-out, flushing", aid2str(i)); >+ if (imsg_compose(ibuf_rde, IMSG_SESSION_FLUSH, >+ p->conf.id, 0, -1, &i, sizeof(i)) == -1) >+ return (-1); >+ } >+ p->capa.neg.grestart.flags[i] &= ~CAPA_GR_RESTARTING; >+ } >+ return (0); >+} >+ >+int > session_dispatch_msg(struct pollfd *pfd, struct peer *p) > { >- ssize_t n, rpos, av, left; >+ ssize_t n; > socklen_t len; >- int error, processed = 0; >- u_int16_t msglen; >- u_int8_t msgtype; >+ int error; > > if (p->state == STATE_CONNECT) { > if (pfd->revents & POLLOUT) { >@@ -1641,71 +1843,83 @@ session_dispatch_msg(struct pollfd *pfd, > return (1); > } > >- rpos = 0; >- av = p->rbuf->wpos + n; >+ p->rbuf->wpos += n; > p->stats.last_read = time(NULL); >+ return (1); >+ } >+ return (0); >+} > >- /* >- * session might drop to IDLE -> buffers deallocated >- * we MUST check rbuf != NULL before use >- */ >- for (;;) { >- if (rpos + MSGSIZE_HEADER > av) >- break; >- if (p->rbuf == NULL) >- break; >- if (parse_header(p, p->rbuf->buf + rpos, &msglen, >- &msgtype) == -1) >- return (0); >- if (rpos + msglen > av) >- break; >- p->rbuf->rptr = p->rbuf->buf + rpos; >- >- switch (msgtype) { >- case OPEN: >- bgp_fsm(p, EVNT_RCVD_OPEN); >- p->stats.msg_rcvd_open++; >- break; >- case UPDATE: >- bgp_fsm(p, EVNT_RCVD_UPDATE); >- p->stats.msg_rcvd_update++; >- break; >- case NOTIFICATION: >- bgp_fsm(p, EVNT_RCVD_NOTIFICATION); >- p->stats.msg_rcvd_notification++; >- break; >- case KEEPALIVE: >- bgp_fsm(p, EVNT_RCVD_KEEPALIVE); >- p->stats.msg_rcvd_keepalive++; >- break; >- case RREFRESH: >- parse_refresh(p); >- p->stats.msg_rcvd_rrefresh++; >- break; >- default: /* cannot happen */ >- session_notification(p, ERR_HEADER, >- ERR_HDR_TYPE, &msgtype, 1); >- log_warnx("received message with " >- "unknown type %u", msgtype); >- bgp_fsm(p, EVNT_CON_FATAL); >- } >- rpos += msglen; >- if (++processed > MSG_PROCESS_LIMIT) >- break; >- } >- if (p->rbuf == NULL) >- return (1); >+int >+session_process_msg(struct peer *p) >+{ >+ ssize_t rpos, av, left; >+ int processed = 0; >+ u_int16_t msglen; >+ u_int8_t msgtype; > >- if (rpos < av) { >- left = av - rpos; >- memcpy(&p->rbuf->buf, p->rbuf->buf + rpos, left); >- p->rbuf->wpos = left; >- } else >- p->rbuf->wpos = 0; >+ rpos = 0; >+ av = p->rbuf->wpos; > >- return (1); >+ /* >+ * session might drop to IDLE -> buffers deallocated >+ * we MUST check rbuf != NULL before use >+ */ >+ for (;;) { >+ if (rpos + MSGSIZE_HEADER > av) >+ break; >+ if (p->rbuf == NULL) >+ break; >+ if (parse_header(p, p->rbuf->buf + rpos, &msglen, >+ &msgtype) == -1) >+ return (0); >+ if (rpos + msglen > av) >+ break; >+ p->rbuf->rptr = p->rbuf->buf + rpos; >+ >+ switch (msgtype) { >+ case OPEN: >+ bgp_fsm(p, EVNT_RCVD_OPEN); >+ p->stats.msg_rcvd_open++; >+ break; >+ case UPDATE: >+ bgp_fsm(p, EVNT_RCVD_UPDATE); >+ p->stats.msg_rcvd_update++; >+ break; >+ case NOTIFICATION: >+ bgp_fsm(p, EVNT_RCVD_NOTIFICATION); >+ p->stats.msg_rcvd_notification++; >+ break; >+ case KEEPALIVE: >+ bgp_fsm(p, EVNT_RCVD_KEEPALIVE); >+ p->stats.msg_rcvd_keepalive++; >+ break; >+ case RREFRESH: >+ parse_refresh(p); >+ p->stats.msg_rcvd_rrefresh++; >+ break; >+ default: /* cannot happen */ >+ session_notification(p, ERR_HEADER, ERR_HDR_TYPE, >+ &msgtype, 1); >+ log_warnx("received message with unknown type %u", >+ msgtype); >+ bgp_fsm(p, EVNT_CON_FATAL); >+ } >+ rpos += msglen; >+ if (++processed > MSG_PROCESS_LIMIT) >+ break; > } >- return (0); >+ if (p->rbuf == NULL) >+ return (1); >+ >+ if (rpos < av) { >+ left = av - rpos; >+ memcpy(&p->rbuf->buf, p->rbuf->buf + rpos, left); >+ p->rbuf->wpos = left; >+ } else >+ p->rbuf->wpos = 0; >+ >+ return (1); > } > > int >@@ -1853,12 +2067,6 @@ parse_open(struct peer *peer) > p += sizeof(short_as); > as = peer->short_as = ntohs(short_as); > >- /* if remote-as is zero and it's a cloned neighbor, accept any */ >- if (peer->conf.cloned && !peer->conf.remote_as && as != AS_TRANS) { >- peer->conf.remote_as = as; >- peer->conf.ebgp = (peer->conf.remote_as != conf->as); >- } >- > memcpy(&oholdtime, p, sizeof(oholdtime)); > p += sizeof(oholdtime); > >@@ -1966,6 +2174,15 @@ parse_open(struct peer *peer) > } > } > >+ /* if remote-as is zero and it's a cloned neighbor, accept any */ >+ if (peer->conf.cloned && !peer->conf.remote_as && as != AS_TRANS) { >+ peer->conf.remote_as = as; >+ peer->conf.ebgp = (peer->conf.remote_as != conf->as); >+ if (!peer->conf.ebgp) >+ /* force enforce_as off for iBGP sessions */ >+ peer->conf.enforce_as = ENFORCE_AS_OFF; >+ } >+ > if (peer->conf.remote_as != as) { > log_peer_warnx(&peer->conf, "peer sent wrong AS %s", > log_as(as)); >@@ -1974,6 +2191,14 @@ parse_open(struct peer *peer) > return (-1); > } > >+ if (capa_neg_calc(peer) == -1) { >+ log_peer_warnx(&peer->conf, >+ "capability negotiation calculation failed"); >+ session_notification(peer, ERR_OPEN, 0, NULL, 0); >+ change_state(peer, STATE_IDLE, EVNT_RCVD_OPEN); >+ return (-1); >+ } >+ > return (0); > } > >@@ -2008,24 +2233,35 @@ int > parse_refresh(struct peer *peer) > { > u_char *p; >- struct rrefresh r; >+ u_int16_t afi; >+ u_int8_t aid, safi; > > p = peer->rbuf->rptr; > p += MSGSIZE_HEADER; /* header is already checked */ > >+ /* >+ * We could check if we actually announced the capability but >+ * as long as the message is correctly encoded we don't care. >+ */ >+ > /* afi, 2 byte */ >- memcpy(&r.afi, p, sizeof(r.afi)); >- r.afi = ntohs(r.afi); >+ memcpy(&afi, p, sizeof(afi)); >+ afi = ntohs(afi); > p += 2; > /* reserved, 1 byte */ > p += 1; > /* safi, 1 byte */ >- memcpy(&r.safi, p, sizeof(r.safi)); >+ memcpy(&safi, p, sizeof(safi)); > > /* afi/safi unchecked - unrecognized values will be ignored anyway */ >+ if (afi2aid(afi, safi, &aid) == -1) { >+ log_peer_warnx(&peer->conf, "peer sent bad refresh, " >+ "invalid afi/safi pair"); >+ return (0); >+ } > >- if (imsg_compose(ibuf_rde, IMSG_REFRESH, peer->conf.id, 0, -1, &r, >- sizeof(r)) == -1) >+ if (imsg_compose(ibuf_rde, IMSG_REFRESH, peer->conf.id, 0, -1, &aid, >+ sizeof(aid)) == -1) > return (-1); > > return (0); >@@ -2035,11 +2271,12 @@ int > parse_notification(struct peer *peer) > { > u_char *p; >+ u_int16_t datalen; > u_int8_t errcode; > u_int8_t subcode; >- u_int16_t datalen; > u_int8_t capa_code; > u_int8_t capa_len; >+ u_int8_t i; > > /* just log */ > p = peer->rbuf->rptr; >@@ -2059,7 +2296,7 @@ parse_notification(struct peer *peer) > p += sizeof(subcode); > datalen -= sizeof(subcode); > >- log_notification(peer, errcode, subcode, p, datalen); >+ log_notification(peer, errcode, subcode, p, datalen, "received"); > peer->errcnt++; > > if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) { >@@ -2094,8 +2331,8 @@ parse_notification(struct peer *peer) > datalen -= capa_len; > switch (capa_code) { > case CAPA_MP: >- peer->capa.ann.mp_v4 = SAFI_NONE; >- peer->capa.ann.mp_v6 = SAFI_NONE; >+ for (i = 0; i < AID_MAX; i++) >+ peer->capa.ann.mp[i] = 0; > log_peer_warnx(&peer->conf, > "disabling multiprotocol capability"); > break; >@@ -2105,7 +2342,7 @@ parse_notification(struct peer *peer) > "disabling route refresh capability"); > break; > case CAPA_RESTART: >- peer->capa.ann.restart = 0; >+ peer->capa.ann.grestart.restart = 0; > log_peer_warnx(&peer->conf, > "disabling restart capability"); > break; >@@ -2139,19 +2376,23 @@ parse_notification(struct peer *peer) > int > parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen, u_int32_t *as) > { >+ u_char *capa_val; >+ u_int32_t remote_as; > u_int16_t len; >+ u_int16_t afi; >+ u_int16_t gr_header; >+ u_int8_t safi; >+ u_int8_t aid; >+ u_int8_t gr_flags; > u_int8_t capa_code; > u_int8_t capa_len; >- u_char *capa_val; >- u_int16_t mp_afi; >- u_int8_t mp_safi; >- u_int32_t remote_as; >+ u_int8_t i; > > len = dlen; > while (len > 0) { > if (len < 2) { >- log_peer_warnx(&peer->conf, "parse_capabilities: " >- "expect len >= 2, len is %u", len); >+ log_peer_warnx(&peer->conf, "Bad capabilities attr " >+ "length: %u, too short", len); > return (-1); > } > memcpy(&capa_code, d, sizeof(capa_code)); >@@ -2163,7 +2404,7 @@ parse_capabilities(struct peer *peer, u_ > if (capa_len > 0) { > if (len < capa_len) { > log_peer_warnx(&peer->conf, >- "parse_capabilities: " >+ "Bad capabilities attr length: " > "len %u smaller than capa_len %u", > len, capa_len); > return (-1); >@@ -2178,47 +2419,82 @@ parse_capabilities(struct peer *peer, u_ > case CAPA_MP: /* RFC 4760 */ > if (capa_len != 4) { > log_peer_warnx(&peer->conf, >- "parse_capabilities: " >- "expect len 4, len is %u", capa_len); >- return (-1); >- } >- memcpy(&mp_afi, capa_val, sizeof(mp_afi)); >- mp_afi = ntohs(mp_afi); >- memcpy(&mp_safi, capa_val + 3, sizeof(mp_safi)); >- switch (mp_afi) { >- case AFI_IPv4: >- if (mp_safi < 1 || mp_safi > 3) >- log_peer_warnx(&peer->conf, >- "parse_capabilities: AFI IPv4, " >- "mp_safi %u unknown", mp_safi); >- else >- peer->capa.peer.mp_v4 = mp_safi; >+ "Bad multi protocol capability length: " >+ "%u", capa_len); > break; >- case AFI_IPv6: >- if (mp_safi < 1 || mp_safi > 3) >- log_peer_warnx(&peer->conf, >- "parse_capabilities: AFI IPv6, " >- "mp_safi %u unknown", mp_safi); >- else >- peer->capa.peer.mp_v6 = mp_safi; >- break; >- default: /* ignore */ >+ } >+ memcpy(&afi, capa_val, sizeof(afi)); >+ afi = ntohs(afi); >+ memcpy(&safi, capa_val + 3, sizeof(safi)); >+ if (afi2aid(afi, safi, &aid) == -1) { >+ log_peer_warnx(&peer->conf, >+ "Received multi protocol capability: " >+ " unknown AFI %u, safi %u pair", >+ afi, safi); > break; > } >+ peer->capa.peer.mp[aid] = 1; > break; > case CAPA_REFRESH: > peer->capa.peer.refresh = 1; > break; > case CAPA_RESTART: >- peer->capa.peer.restart = 1; >- /* we don't care about the further restart capas yet */ >+ if (capa_len == 2) { >+ /* peer only supports EoR marker */ >+ peer->capa.peer.grestart.restart = 1; >+ peer->capa.peer.grestart.timeout = 0; >+ break; >+ } else if (capa_len % 4 != 2) { >+ log_peer_warnx(&peer->conf, >+ "Bad graceful restart capability length: " >+ "%u", capa_len); >+ peer->capa.peer.grestart.restart = 0; >+ peer->capa.peer.grestart.timeout = 0; >+ break; >+ } >+ >+ memcpy(&gr_header, capa_val, sizeof(gr_header)); >+ gr_header = ntohs(gr_header); >+ peer->capa.peer.grestart.timeout = >+ gr_header & CAPA_GR_TIMEMASK; >+ if (peer->capa.peer.grestart.timeout == 0) { >+ log_peer_warnx(&peer->conf, "Received " >+ "graceful restart timeout is zero"); >+ peer->capa.peer.grestart.restart = 0; >+ break; >+ } >+ >+ for (i = 2; i <= capa_len - 4; i += 4) { >+ memcpy(&afi, capa_val + i, sizeof(afi)); >+ afi = ntohs(afi); >+ memcpy(&safi, capa_val + i + 2, sizeof(safi)); >+ if (afi2aid(afi, safi, &aid) == -1) { >+ log_peer_warnx(&peer->conf, >+ "Received graceful restart capa: " >+ " unknown AFI %u, safi %u pair", >+ afi, safi); >+ continue; >+ } >+ memcpy(&gr_flags, capa_val + i + 3, >+ sizeof(gr_flags)); >+ peer->capa.peer.grestart.flags[aid] |= >+ CAPA_GR_PRESENT; >+ if (gr_flags & CAPA_GR_F_FLAG) >+ peer->capa.peer.grestart.flags[aid] |= >+ CAPA_GR_FORWARD; >+ if (gr_header & CAPA_GR_R_FLAG) >+ peer->capa.peer.grestart.flags[aid] |= >+ CAPA_GR_RESTART; >+ peer->capa.peer.grestart.restart = 2; >+ } > break; > case CAPA_AS4BYTE: > if (capa_len != 4) { > log_peer_warnx(&peer->conf, >- "parse_capabilities: " >- "expect len 4, len is %u", capa_len); >- return (-1); >+ "Bad AS4BYTE capability length: " >+ "%u", capa_len); >+ peer->capa.peer.as4byte = 0; >+ break; > } > memcpy(&remote_as, capa_val, sizeof(remote_as)); > *as = ntohl(remote_as); >@@ -2232,6 +2508,66 @@ parse_capabilities(struct peer *peer, u_ > return (0); > } > >+int >+capa_neg_calc(struct peer *p) >+{ >+ u_int8_t i, hasmp = 0; >+ >+ /* refresh: does not realy matter here, use peer setting */ >+ p->capa.neg.refresh = p->capa.peer.refresh; >+ >+ /* as4byte: both side must announce capability */ >+ if (p->capa.ann.as4byte && p->capa.peer.as4byte) >+ p->capa.neg.as4byte = 1; >+ else >+ p->capa.neg.as4byte = 0; >+ >+ /* MP: both side must announce capability */ >+ for (i = 0; i < AID_MAX; i++) { >+ if (p->capa.ann.mp[i] && p->capa.peer.mp[i]) { >+ p->capa.neg.mp[i] = 1; >+ hasmp = 1; >+ } else >+ p->capa.neg.mp[i] = 0; >+ } >+ /* if no MP capability present default to IPv4 unicast mode */ >+ if (!hasmp) >+ p->capa.neg.mp[AID_INET] = 1; >+ >+ /* >+ * graceful restart: only the peer capabilities are of interest here. >+ * It is necessary to compare the new values with the previous ones >+ * and act acordingly. AFI/SAFI that are not part in the MP capability >+ * are treated as not being present. >+ */ >+ >+ for (i = 0; i < AID_MAX; i++) { >+ /* disable GR if the AFI/SAFI is not present */ >+ if (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT && >+ p->capa.neg.mp[i] == 0) >+ p->capa.peer.grestart.flags[i] = 0; /* disable */ >+ /* look at current GR state and decide what to do */ >+ if (p->capa.neg.grestart.flags[i] & CAPA_GR_RESTARTING) { >+ if (!(p->capa.peer.grestart.flags[i] & >+ CAPA_GR_FORWARD)) { >+ if (imsg_compose(ibuf_rde, IMSG_SESSION_FLUSH, >+ p->conf.id, 0, -1, &i, sizeof(i)) == -1) >+ return (-1); >+ log_peer_warnx(&p->conf, "graceful restart of " >+ "%s, not restarted, flushing", aid2str(i)); >+ } >+ p->capa.neg.grestart.flags[i] = >+ p->capa.peer.grestart.flags[i] | CAPA_GR_RESTARTING; >+ } else >+ p->capa.neg.grestart.flags[i] = >+ p->capa.peer.grestart.flags[i]; >+ } >+ p->capa.neg.grestart.timeout = p->capa.peer.grestart.timeout; >+ p->capa.neg.grestart.restart = p->capa.peer.grestart.restart; >+ >+ return (0); >+} >+ > void > session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) > { >@@ -2244,8 +2580,8 @@ session_dispatch_imsg(struct imsgbuf *ib > struct kif *kif; > u_char *data; > enum reconf_action reconf; >- int n, depend_ok; >- u_int8_t errcode, subcode; >+ int n, depend_ok, restricted; >+ u_int8_t aid, errcode, subcode; > > if ((n = imsg_read(ibuf)) == -1) > fatal("session_dispatch_imsg: imsg_read error"); >@@ -2332,15 +2668,42 @@ session_dispatch_imsg(struct imsgbuf *ib > } > > break; >+ case IMSG_RECONF_CTRL: >+ if (idx != PFD_PIPE_MAIN) >+ fatalx("reconf request not from parent"); >+ if (imsg.hdr.len != IMSG_HEADER_SIZE + >+ sizeof(restricted)) >+ fatalx("IFINFO imsg with wrong len"); >+ memcpy(&restricted, imsg.data, sizeof(restricted)); >+ if (imsg.fd == -1) { >+ log_warnx("expected to receive fd for control " >+ "socket but didn't receive any"); >+ break; >+ } >+ if (restricted) { >+ control_shutdown(rcsock); >+ rcsock = imsg.fd; >+ control_listen(rcsock); >+ } else { >+ control_shutdown(csock); >+ csock = imsg.fd; >+ control_listen(csock); >+ } >+ break; > case IMSG_RECONF_DONE: > if (idx != PFD_PIPE_MAIN) > fatalx("reconf request not from parent"); > if (nconf == NULL) > fatalx("got IMSG_RECONF_DONE but no config"); >+ conf->flags = nconf->flags; >+ conf->log = nconf->log; >+ conf->bgpid = nconf->bgpid; >+ conf->clusterid = nconf->clusterid; > conf->as = nconf->as; >+ conf->short_as = nconf->short_as; > conf->holdtime = nconf->holdtime; >- conf->bgpid = nconf->bgpid; > conf->min_holdtime = nconf->min_holdtime; >+ conf->connectretry = nconf->connectretry; > > /* add new peers */ > for (p = npeers; p != NULL; p = next) { >@@ -2388,6 +2751,8 @@ session_dispatch_imsg(struct imsgbuf *ib > nconf = NULL; > pending_reconf = 0; > log_info("SE reconfigured"); >+ imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0, >+ -1, NULL, 0); > break; > case IMSG_IFINFO: > if (idx != PFD_PIPE_MAIN) >@@ -2397,9 +2762,7 @@ session_dispatch_imsg(struct imsgbuf *ib > fatalx("IFINFO imsg with wrong len"); > kif = imsg.data; > depend_ok = (kif->flags & IFF_UP) && >- (LINK_STATE_IS_UP(kif->link_state) || >- (kif->link_state == LINK_STATE_UNKNOWN && >- kif->media_type != IFT_CARP)); >+ LINK_STATE_IS_UP(kif->link_state); > > for (p = peers; p != NULL; p = p->next) > if (!strcmp(p->conf.if_depend, kif->ifname)) { >@@ -2408,7 +2771,8 @@ session_dispatch_imsg(struct imsgbuf *ib > bgp_fsm(p, EVNT_START); > } else if (!depend_ok && p->depend_ok) { > p->depend_ok = depend_ok; >- bgp_fsm(p, EVNT_STOP); >+ session_stop(p, >+ ERR_CEASE_OTHER_CHANGE); > } > } > break; >@@ -2456,10 +2820,10 @@ session_dispatch_imsg(struct imsgbuf *ib > } > break; > case IMSG_CTL_KROUTE: >- case IMSG_CTL_KROUTE6: > case IMSG_CTL_KROUTE_ADDR: > case IMSG_CTL_SHOW_NEXTHOP: > case IMSG_CTL_SHOW_INTERFACE: >+ case IMSG_CTL_SHOW_FIB_TABLES: > if (idx != PFD_PIPE_MAIN) > fatalx("ctl kroute request not from parent"); > control_imsg_relay(&imsg); >@@ -2469,7 +2833,6 @@ session_dispatch_imsg(struct imsgbuf *ib > case IMSG_CTL_SHOW_RIB_ATTR: > case IMSG_CTL_SHOW_RIB_MEM: > case IMSG_CTL_SHOW_NETWORK: >- case IMSG_CTL_SHOW_NETWORK6: > case IMSG_CTL_SHOW_NEIGHBOR: > if (idx != PFD_PIPE_ROUTE_CTL) > fatalx("ctl rib request not from RDE"); >@@ -2531,6 +2894,40 @@ session_dispatch_imsg(struct imsgbuf *ib > break; > } > break; >+ case IMSG_SESSION_RESTARTED: >+ if (idx != PFD_PIPE_ROUTE) >+ fatalx("update request not from RDE"); >+ if (imsg.hdr.len < IMSG_HEADER_SIZE + sizeof(aid)) { >+ log_warnx("RDE sent invalid restart msg"); >+ break; >+ } >+ if ((p = getpeerbyid(imsg.hdr.peerid)) == NULL) { >+ log_warnx("no such peer: id=%u", >+ imsg.hdr.peerid); >+ break; >+ } >+ memcpy(&aid, imsg.data, sizeof(aid)); >+ if (aid >= AID_MAX) >+ fatalx("IMSG_SESSION_RESTARTED: bad AID"); >+ if (p->capa.neg.grestart.flags[aid] & >+ CAPA_GR_RESTARTING && >+ p->capa.neg.grestart.flags[aid] & >+ CAPA_GR_FORWARD) { >+ log_peer_warnx(&p->conf, >+ "graceful restart of %s finished", >+ aid2str(aid)); >+ p->capa.neg.grestart.flags[aid] &= >+ ~CAPA_GR_RESTARTING; >+ timer_stop(p, Timer_RestartTimeout); >+ >+ /* signal back to RDE to cleanup stale routes */ >+ if (imsg_compose(ibuf_rde, >+ IMSG_SESSION_RESTARTED, imsg.hdr.peerid, 0, >+ -1, &aid, sizeof(aid)) == -1) >+ fatal("imsg_compose: " >+ "IMSG_SESSION_RESTARTED"); >+ } >+ break; > default: > break; > } >@@ -2612,29 +3009,23 @@ getpeerbydesc(const char *descr) > struct peer * > getpeerbyip(struct sockaddr *ip) > { >+ struct bgpd_addr addr; > struct peer *p, *newpeer, *loose = NULL; > u_int32_t id; > >+ sa2addr(ip, &addr); >+ > /* we might want a more effective way to find peers by IP */ > for (p = peers; p != NULL; p = p->next) > if (!p->conf.template && >- p->conf.remote_addr.af == ip->sa_family) { >- if (p->conf.remote_addr.af == AF_INET && >- p->conf.remote_addr.v4.s_addr == >- ((struct sockaddr_in *)ip)->sin_addr.s_addr) >- return (p); >- if (p->conf.remote_addr.af == AF_INET6 && >- !bcmp(&p->conf.remote_addr.v6, >- &((struct sockaddr_in6 *)ip)->sin6_addr, >- sizeof(p->conf.remote_addr.v6))) >- return (p); >- } >+ !memcmp(&addr, &p->conf.remote_addr, sizeof(addr))) >+ return (p); > > /* try template matching */ > for (p = peers; p != NULL; p = p->next) > if (p->conf.template && >- p->conf.remote_addr.af == ip->sa_family && >- session_match_mask(p, ip)) >+ p->conf.remote_addr.aid == addr.aid && >+ session_match_mask(p, &addr)) > if (loose == NULL || loose->conf.remote_masklen < > p->conf.remote_masklen) > loose = p; >@@ -2653,21 +3044,19 @@ getpeerbyip(struct sockaddr *ip) > break; > } > } >- if (newpeer->conf.remote_addr.af == AF_INET) { >- newpeer->conf.remote_addr.v4.s_addr = >- ((struct sockaddr_in *)ip)->sin_addr.s_addr; >+ sa2addr(ip, &newpeer->conf.remote_addr); >+ switch (ip->sa_family) { >+ case AF_INET: > newpeer->conf.remote_masklen = 32; >- } >- if (newpeer->conf.remote_addr.af == AF_INET6) { >- memcpy(&p->conf.remote_addr.v6, >- &((struct sockaddr_in6 *)ip)->sin6_addr, >- sizeof(newpeer->conf.remote_addr.v6)); >+ break; >+ case AF_INET6: > newpeer->conf.remote_masklen = 128; >+ break; > } > newpeer->conf.template = 0; > newpeer->conf.cloned = 1; > newpeer->state = newpeer->prev_state = STATE_NONE; >- newpeer->conf.reconf_action = RECONF_REINIT; >+ newpeer->conf.reconf_action = RECONF_KEEP; > newpeer->rbuf = NULL; > init_peer(newpeer); > bgp_fsm(newpeer, EVNT_START); >@@ -2680,40 +3069,24 @@ getpeerbyip(struct sockaddr *ip) > } > > int >-session_match_mask(struct peer *p, struct sockaddr *ip) >+session_match_mask(struct peer *p, struct bgpd_addr *a) > { >- int i; > in_addr_t v4mask; >- struct in6_addr *in; >- struct in6_addr mask; >+ struct in6_addr masked; > >- if (p->conf.remote_addr.af == AF_INET) { >+ switch (p->conf.remote_addr.aid) { >+ case AID_INET: > v4mask = htonl(prefixlen2mask(p->conf.remote_masklen)); >- if (p->conf.remote_addr.v4.s_addr == >- ((((struct sockaddr_in *)ip)->sin_addr.s_addr) & v4mask)) >+ if (p->conf.remote_addr.v4.s_addr == (a->v4.s_addr & v4mask)) > return (1); >- else >- return (0); >- } >- >- if (p->conf.remote_addr.af == AF_INET6) { >- bzero(&mask, sizeof(mask)); >- for (i = 0; i < p->conf.remote_masklen / 8; i++) >- mask.s6_addr[i] = 0xff; >- i = p->conf.remote_masklen % 8; >- if (i) >- mask.s6_addr[p->conf.remote_masklen / 8] = 0xff00 >> i; >- >- in = &((struct sockaddr_in6 *)ip)->sin6_addr; >- >- for (i = 0; i < 16; i++) >- if ((in->s6_addr[i] & mask.s6_addr[i]) != >- p->conf.remote_addr.addr8[i]) >- return (0); >+ return (0); >+ case AID_INET6: >+ inet6applymask(&masked, &a->v6, p->conf.remote_masklen); > >- return (1); >+ if (!memcmp(&masked, &p->conf.remote_addr.v6, sizeof(masked))) >+ return (1); >+ return (0); > } >- > return (0); > } > >@@ -2733,6 +3106,7 @@ getpeerbyid(u_int32_t peerid) > void > session_down(struct peer *peer) > { >+ bzero(&peer->capa.neg, sizeof(peer->capa.neg)); > peer->stats.last_updown = time(NULL); > if (imsg_compose(ibuf_rde, IMSG_SESSION_DOWN, peer->conf.id, 0, -1, > NULL, 0) == -1) >@@ -2744,39 +3118,17 @@ session_up(struct peer *p) > { > struct session_up sup; > >- if (imsg_compose(ibuf_rde, IMSG_SESSION_ADD, p->conf.id, 0, -1, >- &p->conf, sizeof(p->conf)) == -1) >- fatalx("imsg_compose error"); >+ if (!session_graceful_is_restarting(p)) >+ if (imsg_compose(ibuf_rde, IMSG_SESSION_ADD, p->conf.id, 0, -1, >+ &p->conf, sizeof(p->conf)) == -1) >+ fatalx("imsg_compose error"); > >- switch (p->sa_local.ss_family) { >- case AF_INET: >- sup.local_addr.af = AF_INET; >- memcpy(&sup.local_addr.v4, >- &((struct sockaddr_in *)&p->sa_local)->sin_addr, >- sizeof(sup.local_addr.v4)); >- sup.remote_addr.af = AF_INET; >- memcpy(&sup.remote_addr.v4, >- &((struct sockaddr_in *)&p->sa_remote)->sin_addr, >- sizeof(sup.remote_addr.v4)); >- break; >- case AF_INET6: >- sup.local_addr.af = AF_INET6; >- memcpy(&sup.local_addr.v6, >- &((struct sockaddr_in6 *)&p->sa_local)->sin6_addr, >- sizeof(sup.local_addr.v6)); >- sup.remote_addr.af = AF_INET6; >- memcpy(&sup.remote_addr.v6, >- &((struct sockaddr_in6 *)&p->sa_remote)->sin6_addr, >- sizeof(sup.remote_addr.v6)); >- break; >- default: >- fatalx("session_up: unsupported address family"); >- } >+ sa2addr((struct sockaddr *)&p->sa_local, &sup.local_addr); >+ sa2addr((struct sockaddr *)&p->sa_remote, &sup.remote_addr); > > sup.remote_bgpid = p->remote_bgpid; > sup.short_as = p->short_as; >- memcpy(&sup.capa_announced, &p->capa.ann, sizeof(sup.capa_announced)); >- memcpy(&sup.capa_received, &p->capa.peer, sizeof(sup.capa_received)); >+ memcpy(&sup.capa, &p->capa.neg, sizeof(sup.capa)); > p->stats.last_updown = time(NULL); > if (imsg_compose(ibuf_rde, IMSG_SESSION_UP, p->conf.id, 0, -1, > &sup, sizeof(sup)) == -1) >@@ -2784,9 +3136,10 @@ session_up(struct peer *p) > } > > int >-imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen) >+imsg_compose_parent(int type, u_int32_t peerid, pid_t pid, void *data, >+ u_int16_t datalen) > { >- return (imsg_compose(ibuf_main, type, 0, pid, -1, data, datalen)); >+ return (imsg_compose(ibuf_main, type, peerid, pid, -1, data, datalen)); > } > > int >@@ -2795,34 +3148,6 @@ imsg_compose_rde(int type, pid_t pid, vo > return (imsg_compose(ibuf_rde, type, 0, pid, -1, data, datalen)); > } > >-static struct sockaddr * >-addr2sa(struct bgpd_addr *addr, u_int16_t port) >-{ >- static struct sockaddr_storage ss; >- struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; >- struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; >- >- bzero(&ss, sizeof(ss)); >- switch (addr->af) { >- case AF_INET: >- sa_in->sin_family = AF_INET; >- sa_in->sin_len = sizeof(struct sockaddr_in); >- sa_in->sin_addr.s_addr = addr->v4.s_addr; >- sa_in->sin_port = htons(port); >- break; >- case AF_INET6: >- sa_in6->sin6_family = AF_INET6; >- sa_in6->sin6_len = sizeof(struct sockaddr_in6); >- memcpy(&sa_in6->sin6_addr, &addr->v6, >- sizeof(sa_in6->sin6_addr)); >- sa_in6->sin6_port = htons(port); >- sa_in6->sin6_scope_id = addr->scope_id; >- break; >- } >- >- return ((struct sockaddr *)&ss); >-} >- > void > session_demote(struct peer *p, int level) > { >@@ -2837,3 +3162,19 @@ session_demote(struct peer *p, int level > > p->demoted += level; > } >+ >+void >+session_stop(struct peer *peer, u_int8_t subcode) >+{ >+ switch (peer->state) { >+ case STATE_OPENSENT: >+ case STATE_OPENCONFIRM: >+ case STATE_ESTABLISHED: >+ session_notification(peer, ERR_CEASE, subcode, NULL, 0); >+ break; >+ default: >+ /* session not open, no need to send notification */ >+ break; >+ } >+ bgp_fsm(peer, EVNT_STOP); >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 223835
:
188239
|
188240
|
190461
| 191795