ports/net/openbgpd/files/patch-bgpd_session.c
2009-11-02 07:09:37 +00:00

570 lines
18 KiB
C

Index: bgpd/session.c
===================================================================
RCS file: /home/cvs/private/hrs/openbgpd/bgpd/session.c,v
retrieving revision 1.1.1.1
retrieving revision 1.5
diff -u -p -r1.1.1.1 -r1.5
--- bgpd/session.c 30 Jun 2009 05:46:15 -0000 1.1.1.1
+++ bgpd/session.c 22 Oct 2009 15:10:02 -0000 1.5
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.282 2008/06/26 00:01:51 claudio Exp $ */
+/* $OpenBSD: session.c,v 1.294 2009/07/24 13:09:29 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
@@ -52,6 +52,10 @@
#define PFD_SOCK_RCTL 4
#define PFD_LISTENERS_START 5
+#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 *);
void init_conf(struct bgpd_config *);
@@ -65,8 +69,7 @@ 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(struct buf *, u_int8_t, u_int8_t);
int session_capa_add_mp(struct buf *, u_int16_t, u_int8_t);
struct bgp_msg *session_newmsg(enum msg_type, u_int16_t);
int session_sendmsg(struct bgp_msg *, struct peer *);
@@ -177,8 +180,8 @@ 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, int pipe_m2s[2], int pipe_s2r[2], int pipe_m2r[2],
- int pipe_s2rctl[2])
+ 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])
{
int nfds, timeout;
unsigned int i, j, idx_peers, idx_listeners, idx_mrts;
@@ -195,6 +198,7 @@ session_main(struct bgpd_config *config,
struct pollfd *pfd = NULL;
struct ctl_conn *ctl_conn;
struct listen_addr *la;
+ struct rde_rib *rr;
void *newp;
short events;
@@ -283,6 +287,11 @@ session_main(struct bgpd_config *config,
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);
+ }
while (session_quit == 0) {
/* check for peers to be initialized or deleted */
@@ -302,7 +311,7 @@ session_main(struct bgpd_config *config,
/* reinit due? */
if (p->conf.reconf_action == RECONF_REINIT) {
- bgp_fsm(p, EVNT_STOP);
+ session_stop(p, ERR_CEASE_ADMIN_RESET);
timer_set(p, Timer_IdleHold, 0);
}
@@ -311,7 +320,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;
@@ -341,7 +350,7 @@ session_main(struct bgpd_config *config,
mrt_cnt = 0;
LIST_FOREACH(m, &mrthead, entry)
- if (m->queued)
+ if (m->wbuf.queued)
mrt_cnt++;
if (mrt_cnt > mrt_l_elms) {
@@ -438,6 +447,12 @@ session_main(struct bgpd_config *config,
Timer_IdleHoldReset,
p->IdleHoldTime);
break;
+ case Timer_CarpUndemote:
+ timer_stop(p, Timer_CarpUndemote);
+ if (p->demoted &&
+ p->state == STATE_ESTABLISHED)
+ session_demote(p, -1);
+ break;
default:
fatalx("King Bula lost in time");
}
@@ -446,17 +461,6 @@ session_main(struct bgpd_config *config,
nextaction < timeout)
timeout = nextaction;
- /* XXX carp demotion */
- if (p->demoted && p->state == STATE_ESTABLISHED) {
- if (time(NULL) - p->stats.last_updown >=
- INTERVAL_HOLD_DEMOTED)
- session_demote(p, -1);
- if (p->stats.last_updown + INTERVAL_HOLD_DEMOTED
- - time(NULL) < timeout)
- timeout = p->stats.last_updown +
- INTERVAL_HOLD_DEMOTED - time(NULL);
- }
-
/* are we waiting for a write? */
events = POLLIN;
if (p->wbuf.queued > 0 || p->state == STATE_CONNECT)
@@ -474,8 +478,8 @@ session_main(struct bgpd_config *config,
idx_peers = i;
LIST_FOREACH(m, &mrthead, entry)
- if (m->queued) {
- pfd[i].fd = m->fd;
+ if (m->wbuf.queued) {
+ pfd[i].fd = m->wbuf.fd;
pfd[i].events = POLLOUT;
mrt_l[i - idx_peers] = m;
i++;
@@ -556,7 +560,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);
}
@@ -594,6 +598,8 @@ init_conf(struct bgpd_config *c)
{
if (!c->holdtime)
c->holdtime = INTERVAL_HOLD;
+ if (!c->connectretry)
+ c->connectretry = INTERVAL_CONNECTRETRY;
}
void
@@ -668,7 +674,7 @@ bgp_fsm(struct peer *peer, enum session_
} else {
change_state(peer, STATE_CONNECT, event);
timer_set(peer, Timer_ConnectRetry,
- INTERVAL_CONNECTRETRY);
+ conf->connectretry);
session_connect(peer);
}
peer->passive = 0;
@@ -693,13 +699,13 @@ bgp_fsm(struct peer *peer, enum session_
break;
case EVNT_CON_OPENFAIL:
timer_set(peer, Timer_ConnectRetry,
- INTERVAL_CONNECTRETRY);
+ conf->connectretry);
session_close_connection(peer);
change_state(peer, STATE_ACTIVE, event);
break;
case EVNT_TIMER_CONNRETRY:
timer_set(peer, Timer_ConnectRetry,
- INTERVAL_CONNECTRETRY);
+ conf->connectretry);
session_connect(peer);
break;
default:
@@ -722,7 +728,7 @@ bgp_fsm(struct peer *peer, enum session_
break;
case EVNT_CON_OPENFAIL:
timer_set(peer, Timer_ConnectRetry,
- INTERVAL_CONNECTRETRY);
+ conf->connectretry);
session_close_connection(peer);
change_state(peer, STATE_ACTIVE, event);
break;
@@ -743,13 +749,12 @@ 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:
session_close_connection(peer);
timer_set(peer, Timer_ConnectRetry,
- INTERVAL_CONNECTRETRY);
+ conf->connectretry);
change_state(peer, STATE_ACTIVE, event);
break;
case EVNT_CON_FATAL:
@@ -788,7 +793,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:
@@ -823,7 +827,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:
@@ -953,6 +956,9 @@ change_state(struct peer *peer, enum ses
break;
case STATE_ESTABLISHED:
timer_set(peer, Timer_IdleHoldReset, peer->IdleHoldTime);
+ if (peer->demoted)
+ timer_set(peer, Timer_CarpUndemote,
+ INTERVAL_HOLD_DEMOTED);
session_up(peer);
break;
default: /* something seriously fucked */
@@ -961,13 +967,12 @@ change_state(struct peer *peer, enum ses
log_statechange(peer, state, event);
LIST_FOREACH(mrt, &mrthead, entry) {
- if (mrt->type != MRT_ALL_IN && mrt->type != MRT_ALL_OUT)
+ if (!(mrt->type == MRT_ALL_IN || mrt->type == MRT_ALL_OUT))
continue;
if ((mrt->peer_id == 0 && mrt->group_id == 0) ||
- mrt->peer_id == peer->conf.id ||
- mrt->group_id == peer->conf.groupid)
- mrt_dump_state(mrt, peer->state, state,
- peer, conf);
+ mrt->peer_id == peer->conf.id || (mrt->group_id != 0 &&
+ mrt->group_id == peer->conf.groupid))
+ mrt_dump_state(mrt, peer->state, state, peer);
}
peer->prev_state = peer->state;
peer->state = state;
@@ -1247,21 +1252,12 @@ session_capa_ann_none(struct peer *peer)
}
int
-session_capa_add(struct peer *p, struct buf *opb, u_int8_t capa_code,
- u_int8_t capa_len, u_int8_t *optparamlen)
+session_capa_add(struct buf *opb, u_int8_t capa_code, u_int8_t capa_len)
{
- u_int8_t op_type, op_len, tot_len, errs = 0;
+ int 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;
- if (buf_grow(opb, tot_len) == NULL)
- return (1);
- 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;
return (errs);
}
@@ -1317,22 +1313,16 @@ session_sendmsg(struct bgp_msg *msg, str
struct mrt *mrt;
LIST_FOREACH(mrt, &mrthead, entry) {
- if (mrt->type != MRT_ALL_OUT &&
- msg->type == UPDATE && mrt->type != MRT_UPDATE_OUT)
+ if (!(mrt->type == MRT_ALL_OUT || (msg->type == UPDATE &&
+ mrt->type == MRT_UPDATE_OUT)))
continue;
if ((mrt->peer_id == 0 && mrt->group_id == 0) ||
- mrt->peer_id == p->conf.id ||
- mrt->group_id == p->conf.groupid)
- mrt_dump_bgp_msg(mrt, msg->buf->buf, msg->len, p, conf);
- }
-
- if (buf_close(&p->wbuf, msg->buf) == -1) {
- log_peer_warn(&p->conf, "session_sendmsg buf_close");
- buf_free(msg->buf);
- free(msg);
- return (-1);
+ mrt->peer_id == p->conf.id || (mrt->group_id == 0 &&
+ mrt->group_id == p->conf.groupid))
+ mrt_dump_bgp_msg(mrt, msg->buf->buf, msg->len, p);
}
+ buf_close(&p->wbuf, msg->buf);
free(msg);
return (0);
}
@@ -1344,36 +1334,37 @@ session_open(struct peer *p)
struct buf *opb;
struct msg_open msg;
u_int16_t len;
- u_int8_t optparamlen = 0;
+ u_int8_t op_type, optparamlen = 0;
u_int errs = 0;
- if ((opb = buf_open(0)) == NULL) {
+ if ((opb = buf_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(opb, CAPA_MP, 4);
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(opb, CAPA_MP, 4);
errs += session_capa_add_mp(opb, AFI_IPv6, p->capa.ann.mp_v6);
}
/* 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);
+ c[1] = 0;
+ errs += session_capa_add(opb, CAPA_RESTART, 2);
errs += buf_add(opb, &c, 2);
}
@@ -1382,10 +1373,14 @@ 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 += buf_add(opb, &nas, sizeof(nas));
}
+ if (buf_size(opb))
+ optparamlen = buf_size(opb) + sizeof(op_type) +
+ sizeof(optparamlen);
+
len = MSGSIZE_OPEN_MIN + optparamlen;
if (errs || (buf = session_newmsg(OPEN, len)) == NULL) {
buf_free(opb);
@@ -1394,10 +1389,7 @@ session_open(struct peer *p)
}
msg.version = 4;
- if (conf->as > USHRT_MAX)
- msg.myas = htons(conf->short_as);
- else
- msg.myas = htons(conf->as);
+ msg.myas = htons(conf->short_as);
if (p->conf.holdtime)
msg.holdtime = htons(p->conf.holdtime);
else
@@ -1411,8 +1403,13 @@ session_open(struct peer *p)
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);
+ if (optparamlen) {
+ op_type = OPT_PARAM_CAPABILITIES;
+ optparamlen = buf_size(opb);
+ errs += buf_add(buf->buf, &op_type, sizeof(op_type));
+ errs += buf_add(buf->buf, &optparamlen, sizeof(optparamlen));
+ errs += buf_add(buf->buf, opb->buf, buf_size(opb));
+ }
buf_free(opb);
@@ -1487,7 +1484,6 @@ session_notification(struct peer *p, u_i
{
struct bgp_msg *buf;
u_int errs = 0;
- u_int8_t null8 = 0;
if (p->stats.last_sent_errcode) /* some notification already sent */
return;
@@ -1499,10 +1495,7 @@ session_notification(struct peer *p, u_i
}
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 += buf_add(buf->buf, &subcode, sizeof(subcode));
if (datalen > 0)
errs += buf_add(buf->buf, data, datalen);
@@ -1809,13 +1802,13 @@ parse_header(struct peer *peer, u_char *
return (-1);
}
LIST_FOREACH(mrt, &mrthead, entry) {
- if (mrt->type != MRT_ALL_IN && (mrt->type != MRT_UPDATE_IN ||
- *type != UPDATE))
+ if (!(mrt->type == MRT_ALL_IN || (*type == UPDATE &&
+ mrt->type == MRT_UPDATE_IN)))
continue;
if ((mrt->peer_id == 0 && mrt->group_id == 0) ||
- mrt->peer_id == peer->conf.id ||
- mrt->group_id == peer->conf.groupid)
- mrt_dump_bgp_msg(mrt, data, *len, peer, conf);
+ mrt->peer_id == peer->conf.id || (mrt->group_id != 0 &&
+ mrt->group_id == peer->conf.groupid))
+ mrt_dump_bgp_msg(mrt, data, *len, peer);
}
return (0);
}
@@ -1859,12 +1852,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);
@@ -1972,6 +1959,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));
@@ -2193,22 +2189,20 @@ parse_capabilities(struct peer *peer, u_
memcpy(&mp_safi, capa_val + 3, sizeof(mp_safi));
switch (mp_afi) {
case AFI_IPv4:
- if (mp_safi < 1 || mp_safi > 3) {
+ if (mp_safi < 1 || mp_safi > 3)
log_peer_warnx(&peer->conf,
"parse_capabilities: AFI IPv4, "
- "mp_safi %u illegal", mp_safi);
- return (-1);
- }
- peer->capa.peer.mp_v4 = mp_safi;
+ "mp_safi %u unknown", mp_safi);
+ else
+ peer->capa.peer.mp_v4 = mp_safi;
break;
case AFI_IPv6:
- if (mp_safi < 1 || mp_safi > 3) {
+ if (mp_safi < 1 || mp_safi > 3)
log_peer_warnx(&peer->conf,
"parse_capabilities: AFI IPv6, "
- "mp_safi %u illegal", mp_safi);
- return (-1);
- }
- peer->capa.peer.mp_v6 = mp_safi;
+ "mp_safi %u unknown", mp_safi);
+ else
+ peer->capa.peer.mp_v6 = mp_safi;
break;
default: /* ignore */
break;
@@ -2318,7 +2312,7 @@ session_dispatch_imsg(struct imsgbuf *ib
fatalx("king bula sez: "
"expected REINIT");
- if ((nla->fd = imsg_get_fd(ibuf)) == -1)
+ if ((nla->fd = imsg.fd) == -1)
log_warnx("expected to receive fd for "
"%s but didn't receive any",
log_sockaddr((struct sockaddr *)
@@ -2416,7 +2410,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;
@@ -2429,7 +2424,7 @@ session_dispatch_imsg(struct imsgbuf *ib
}
memcpy(&xmrt, imsg.data, sizeof(struct mrt));
- if ((xmrt.fd = imsg_get_fd(ibuf)) == -1)
+ if ((xmrt.wbuf.fd = imsg.fd) == -1)
log_warnx("expected to receive fd for mrt dump "
"but didn't receive any");
@@ -2440,12 +2435,12 @@ session_dispatch_imsg(struct imsgbuf *ib
if (mrt == NULL)
fatal("session_dispatch_imsg");
memcpy(mrt, &xmrt, sizeof(struct mrt));
- TAILQ_INIT(&mrt->bufs);
+ TAILQ_INIT(&mrt->wbuf.bufs);
LIST_INSERT_HEAD(&mrthead, mrt, entry);
} else {
/* old dump reopened */
- close(mrt->fd);
- mrt->fd = xmrt.fd;
+ close(mrt->wbuf.fd);
+ mrt->wbuf.fd = xmrt.wbuf.fd;
}
break;
case IMSG_MRT_CLOSE:
@@ -2667,7 +2662,7 @@ getpeerbyip(struct sockaddr *ip)
newpeer->conf.remote_masklen = 32;
}
if (newpeer->conf.remote_addr.af == AF_INET6) {
- memcpy(&p->conf.remote_addr.v6,
+ memcpy(&newpeer->conf.remote_addr.v6,
&((struct sockaddr_in6 *)ip)->sin6_addr,
sizeof(newpeer->conf.remote_addr.v6));
newpeer->conf.remote_masklen = 128;
@@ -2675,7 +2670,7 @@ getpeerbyip(struct sockaddr *ip)
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);
@@ -2845,3 +2840,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);
+}