4 * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
6 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
7 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29 static __inline
int nbr_id_compare(struct nbr
*, struct nbr
*);
30 static __inline
int nbr_addr_compare(struct nbr
*, struct nbr
*);
31 static __inline
int nbr_pid_compare(struct nbr
*, struct nbr
*);
32 static void nbr_update_peerid(struct nbr
*);
33 static int nbr_ktimer(struct thread
*);
34 static void nbr_start_ktimer(struct nbr
*);
35 static int nbr_ktimeout(struct thread
*);
36 static void nbr_start_ktimeout(struct nbr
*);
37 static int nbr_itimeout(struct thread
*);
38 static void nbr_start_itimeout(struct nbr
*);
39 static int nbr_idtimer(struct thread
*);
40 static int nbr_act_session_operational(struct nbr
*);
41 static void nbr_send_labelmappings(struct nbr
*);
43 RB_GENERATE(nbr_id_head
, nbr
, id_tree
, nbr_id_compare
)
44 RB_GENERATE(nbr_addr_head
, nbr
, addr_tree
, nbr_addr_compare
)
45 RB_GENERATE(nbr_pid_head
, nbr
, pid_tree
, nbr_pid_compare
)
50 enum nbr_action action
;
53 /* current state event that happened action to take resulting state */
55 {NBR_STA_PRESENT
, NBR_EVT_MATCH_ADJ
, NBR_ACT_NOTHING
, NBR_STA_INITIAL
},
56 {NBR_STA_INITIAL
, NBR_EVT_INIT_RCVD
, NBR_ACT_PASSIVE_INIT
, NBR_STA_OPENREC
},
57 {NBR_STA_OPENREC
, NBR_EVT_KEEPALIVE_RCVD
, NBR_ACT_SESSION_EST
, NBR_STA_OPER
},
59 {NBR_STA_PRESENT
, NBR_EVT_CONNECT_UP
, NBR_ACT_CONNECT_SETUP
, NBR_STA_INITIAL
},
60 {NBR_STA_INITIAL
, NBR_EVT_INIT_SENT
, NBR_ACT_NOTHING
, NBR_STA_OPENSENT
},
61 {NBR_STA_OPENSENT
, NBR_EVT_INIT_RCVD
, NBR_ACT_KEEPALIVE_SEND
, NBR_STA_OPENREC
},
62 /* Session Maintenance */
63 {NBR_STA_OPER
, NBR_EVT_PDU_RCVD
, NBR_ACT_RST_KTIMEOUT
, 0},
64 {NBR_STA_SESSION
, NBR_EVT_PDU_RCVD
, NBR_ACT_NOTHING
, 0},
65 {NBR_STA_OPER
, NBR_EVT_PDU_SENT
, NBR_ACT_RST_KTIMER
, 0},
66 {NBR_STA_SESSION
, NBR_EVT_PDU_SENT
, NBR_ACT_NOTHING
, 0},
68 {NBR_STA_PRESENT
, NBR_EVT_CLOSE_SESSION
, NBR_ACT_NOTHING
, 0},
69 {NBR_STA_SESSION
, NBR_EVT_CLOSE_SESSION
, NBR_ACT_CLOSE_SESSION
, NBR_STA_PRESENT
},
70 {-1, NBR_EVT_NOTHING
, NBR_ACT_NOTHING
, 0},
73 const char * const nbr_event_names
[] = {
85 const char * const nbr_action_names
[] = {
87 "RESET KEEPALIVE TIMEOUT",
88 "START NEIGHBOR SESSION",
89 "RESET KEEPALIVE TIMER",
90 "SETUP NEIGHBOR CONNECTION",
91 "SEND INIT AND KEEPALIVE",
96 struct nbr_id_head nbrs_by_id
= RB_INITIALIZER(&nbrs_by_id
);
97 struct nbr_addr_head nbrs_by_addr
= RB_INITIALIZER(&nbrs_by_addr
);
98 struct nbr_pid_head nbrs_by_pid
= RB_INITIALIZER(&nbrs_by_pid
);
101 nbr_id_compare(struct nbr
*a
, struct nbr
*b
)
103 return (ntohl(a
->id
.s_addr
) - ntohl(b
->id
.s_addr
));
107 nbr_addr_compare(struct nbr
*a
, struct nbr
*b
)
114 return (ldp_addrcmp(a
->af
, &a
->raddr
, &b
->raddr
));
118 nbr_pid_compare(struct nbr
*a
, struct nbr
*b
)
120 return (a
->peerid
- b
->peerid
);
124 nbr_fsm(struct nbr
*nbr
, enum nbr_event event
)
131 old_state
= nbr
->state
;
132 for (i
= 0; nbr_fsm_tbl
[i
].state
!= -1; i
++)
133 if ((nbr_fsm_tbl
[i
].state
& old_state
) &&
134 (nbr_fsm_tbl
[i
].event
== event
)) {
135 new_state
= nbr_fsm_tbl
[i
].new_state
;
139 if (nbr_fsm_tbl
[i
].state
== -1) {
140 /* event outside of the defined fsm, ignore it. */
141 log_warnx("%s: lsr-id %s, event %s not expected in "
142 "state %s", __func__
, inet_ntoa(nbr
->id
),
143 nbr_event_names
[event
], nbr_state_name(old_state
));
148 nbr
->state
= new_state
;
150 if (old_state
!= nbr
->state
) {
151 log_debug("%s: event %s resulted in action %s and "
152 "changing state for lsr-id %s from %s to %s",
153 __func__
, nbr_event_names
[event
],
154 nbr_action_names
[nbr_fsm_tbl
[i
].action
],
155 inet_ntoa(nbr
->id
), nbr_state_name(old_state
),
156 nbr_state_name(nbr
->state
));
158 if (nbr
->state
== NBR_STA_OPER
) {
159 gettimeofday(&now
, NULL
);
160 nbr
->uptime
= now
.tv_sec
;
164 if (nbr
->state
== NBR_STA_OPER
|| nbr
->state
== NBR_STA_PRESENT
)
165 nbr_stop_itimeout(nbr
);
167 nbr_start_itimeout(nbr
);
169 switch (nbr_fsm_tbl
[i
].action
) {
170 case NBR_ACT_RST_KTIMEOUT
:
171 nbr_start_ktimeout(nbr
);
173 case NBR_ACT_RST_KTIMER
:
174 nbr_start_ktimer(nbr
);
176 case NBR_ACT_SESSION_EST
:
177 nbr_act_session_operational(nbr
);
178 nbr_start_ktimer(nbr
);
179 nbr_start_ktimeout(nbr
);
181 send_address_all(nbr
, AF_INET
);
183 send_address_all(nbr
, AF_INET6
);
184 nbr_send_labelmappings(nbr
);
186 case NBR_ACT_CONNECT_SETUP
:
187 nbr
->tcp
= tcp_new(nbr
->fd
, nbr
);
189 /* trigger next state */
191 nbr_fsm(nbr
, NBR_EVT_INIT_SENT
);
193 case NBR_ACT_PASSIVE_INIT
:
197 case NBR_ACT_KEEPALIVE_SEND
:
198 nbr_start_ktimeout(nbr
);
201 case NBR_ACT_CLOSE_SESSION
:
202 ldpe_imsg_compose_lde(IMSG_NEIGHBOR_DOWN
, nbr
->peerid
, 0,
206 case NBR_ACT_NOTHING
:
215 nbr_new(struct in_addr id
, int af
, int ds_tlv
, union ldpd_addr
*addr
,
219 struct nbr_params
*nbrp
;
221 struct pending_conn
*pconn
;
223 log_debug("%s: lsr-id %s transport-address %s", __func__
,
224 inet_ntoa(id
), log_addr(af
, addr
));
226 if ((nbr
= calloc(1, sizeof(*nbr
))) == NULL
)
229 LIST_INIT(&nbr
->adj_list
);
230 nbr
->state
= NBR_STA_PRESENT
;
233 nbr
->ds_tlv
= ds_tlv
;
234 if (af
== AF_INET
|| ds_tlv
)
236 if (af
== AF_INET6
|| ds_tlv
)
239 nbr
->laddr
= (ldp_af_conf_get(leconf
, af
))->trans_addr
;
241 nbr
->raddr_scope
= scope_id
;
242 nbr
->conf_seqnum
= 0;
244 LIST_FOREACH(adj
, &global
.adj_list
, global_entry
) {
245 if (adj
->lsr_id
.s_addr
== nbr
->id
.s_addr
) {
247 LIST_INSERT_HEAD(&nbr
->adj_list
, adj
, nbr_entry
);
251 if (RB_INSERT(nbr_id_head
, &nbrs_by_id
, nbr
) != NULL
)
252 fatalx("nbr_new: RB_INSERT(nbrs_by_id) failed");
253 if (RB_INSERT(nbr_addr_head
, &nbrs_by_addr
, nbr
) != NULL
)
254 fatalx("nbr_new: RB_INSERT(nbrs_by_addr) failed");
256 TAILQ_INIT(&nbr
->mapping_list
);
257 TAILQ_INIT(&nbr
->withdraw_list
);
258 TAILQ_INIT(&nbr
->request_list
);
259 TAILQ_INIT(&nbr
->release_list
);
260 TAILQ_INIT(&nbr
->abortreq_list
);
262 nbrp
= nbr_params_find(leconf
, nbr
->id
);
265 if (pfkey_establish(nbr
, nbrp
) == -1)
266 fatalx("pfkey setup failed");
269 (ldp_af_global_get(&global
, nbr
->af
))->ldp_session_socket
,
270 nbr
->af
, &nbr
->raddr
, nbrp
->auth
.md5key
);
274 pconn
= pending_conn_find(nbr
->af
, &nbr
->raddr
);
276 session_accept_nbr(nbr
, pconn
->fd
);
277 pending_conn_del(pconn
);
284 nbr_del(struct nbr
*nbr
)
286 log_debug("%s: lsr-id %s", __func__
, inet_ntoa(nbr
->id
));
288 nbr_fsm(nbr
, NBR_EVT_CLOSE_SESSION
);
293 (ldp_af_global_get(&global
, nbr
->af
))->ldp_session_socket
,
294 nbr
->af
, &nbr
->raddr
, NULL
);
297 if (nbr_pending_connect(nbr
))
298 THREAD_WRITE_OFF(nbr
->ev_connect
);
299 nbr_stop_ktimer(nbr
);
300 nbr_stop_ktimeout(nbr
);
301 nbr_stop_itimeout(nbr
);
302 nbr_stop_idtimer(nbr
);
304 mapping_list_clr(&nbr
->mapping_list
);
305 mapping_list_clr(&nbr
->withdraw_list
);
306 mapping_list_clr(&nbr
->request_list
);
307 mapping_list_clr(&nbr
->release_list
);
308 mapping_list_clr(&nbr
->abortreq_list
);
311 RB_REMOVE(nbr_pid_head
, &nbrs_by_pid
, nbr
);
312 RB_REMOVE(nbr_id_head
, &nbrs_by_id
, nbr
);
313 RB_REMOVE(nbr_addr_head
, &nbrs_by_addr
, nbr
);
319 nbr_update_peerid(struct nbr
*nbr
)
321 static uint32_t peercnt
= 1;
324 RB_REMOVE(nbr_pid_head
, &nbrs_by_pid
, nbr
);
326 /* get next unused peerid */
327 while (nbr_find_peerid(++peercnt
))
329 nbr
->peerid
= peercnt
;
331 if (RB_INSERT(nbr_pid_head
, &nbrs_by_pid
, nbr
) != NULL
)
332 fatalx("nbr_update_peerid: RB_INSERT(nbrs_by_pid) failed");
336 nbr_find_ldpid(uint32_t lsr_id
)
339 n
.id
.s_addr
= lsr_id
;
340 return (RB_FIND(nbr_id_head
, &nbrs_by_id
, &n
));
344 nbr_find_addr(int af
, union ldpd_addr
*addr
)
349 return (RB_FIND(nbr_addr_head
, &nbrs_by_addr
, &n
));
353 nbr_find_peerid(uint32_t peerid
)
357 return (RB_FIND(nbr_pid_head
, &nbrs_by_pid
, &n
));
361 nbr_adj_count(struct nbr
*nbr
, int af
)
366 LIST_FOREACH(adj
, &nbr
->adj_list
, nbr_entry
)
367 if (adj_get_af(adj
) == af
)
374 nbr_session_active_role(struct nbr
*nbr
)
376 if (ldp_addrcmp(nbr
->af
, &nbr
->laddr
, &nbr
->raddr
) > 0)
384 /* Keepalive timer: timer to send keepalive message to neighbors */
387 nbr_ktimer(struct thread
*thread
)
389 struct nbr
*nbr
= THREAD_ARG(thread
);
391 nbr
->keepalive_timer
= NULL
;
393 nbr_start_ktimer(nbr
);
399 nbr_start_ktimer(struct nbr
*nbr
)
403 /* send three keepalives per period */
404 secs
= nbr
->keepalive
/ KEEPALIVE_PER_PERIOD
;
405 THREAD_TIMER_OFF(nbr
->keepalive_timer
);
406 nbr
->keepalive_timer
= thread_add_timer(master
, nbr_ktimer
, nbr
, secs
);
410 nbr_stop_ktimer(struct nbr
*nbr
)
412 THREAD_TIMER_OFF(nbr
->keepalive_timer
);
415 /* Keepalive timeout: if the nbr hasn't sent keepalive */
418 nbr_ktimeout(struct thread
*thread
)
420 struct nbr
*nbr
= THREAD_ARG(thread
);
422 nbr
->keepalive_timeout
= NULL
;
424 log_debug("%s: lsr-id %s", __func__
, inet_ntoa(nbr
->id
));
426 session_shutdown(nbr
, S_KEEPALIVE_TMR
, 0, 0);
432 nbr_start_ktimeout(struct nbr
*nbr
)
434 THREAD_TIMER_OFF(nbr
->keepalive_timeout
);
435 nbr
->keepalive_timeout
= thread_add_timer(master
, nbr_ktimeout
, nbr
,
440 nbr_stop_ktimeout(struct nbr
*nbr
)
442 THREAD_TIMER_OFF(nbr
->keepalive_timeout
);
445 /* Session initialization timeout: if nbr got stuck in the initialization FSM */
448 nbr_itimeout(struct thread
*thread
)
450 struct nbr
*nbr
= THREAD_ARG(thread
);
452 log_debug("%s: lsr-id %s", __func__
, inet_ntoa(nbr
->id
));
454 nbr_fsm(nbr
, NBR_EVT_CLOSE_SESSION
);
460 nbr_start_itimeout(struct nbr
*nbr
)
464 secs
= INIT_FSM_TIMEOUT
;
465 THREAD_TIMER_OFF(nbr
->init_timeout
);
466 nbr
->init_timeout
= thread_add_timer(master
, nbr_itimeout
, nbr
, secs
);
470 nbr_stop_itimeout(struct nbr
*nbr
)
472 THREAD_TIMER_OFF(nbr
->init_timeout
);
475 /* Init delay timer: timer to retry to iniziatize session */
478 nbr_idtimer(struct thread
*thread
)
480 struct nbr
*nbr
= THREAD_ARG(thread
);
482 nbr
->initdelay_timer
= NULL
;
484 log_debug("%s: lsr-id %s", __func__
, inet_ntoa(nbr
->id
));
486 nbr_establish_connection(nbr
);
492 nbr_start_idtimer(struct nbr
*nbr
)
496 secs
= INIT_DELAY_TMR
;
497 switch(nbr
->idtimer_cnt
) {
499 /* do not further increase the counter */
500 secs
= MAX_DELAY_TMR
;
513 THREAD_TIMER_OFF(nbr
->initdelay_timer
);
514 nbr
->initdelay_timer
= thread_add_timer(master
, nbr_idtimer
, nbr
, secs
);
518 nbr_stop_idtimer(struct nbr
*nbr
)
520 THREAD_TIMER_OFF(nbr
->initdelay_timer
);
524 nbr_pending_idtimer(struct nbr
*nbr
)
526 return (nbr
->initdelay_timer
!= NULL
);
530 nbr_pending_connect(struct nbr
*nbr
)
532 return (nbr
->ev_connect
!= NULL
);
536 nbr_connect_cb(struct thread
*thread
)
538 struct nbr
*nbr
= THREAD_ARG(thread
);
542 nbr
->ev_connect
= NULL
;
545 if (getsockopt(nbr
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &len
) < 0) {
546 log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__
);
553 log_debug("%s: error while connecting to %s: %s", __func__
,
554 log_addr(nbr
->af
, &nbr
->raddr
), strerror(errno
));
558 nbr_fsm(nbr
, NBR_EVT_CONNECT_UP
);
564 nbr_establish_connection(struct nbr
*nbr
)
566 struct sockaddr_storage local_sa
;
567 struct sockaddr_storage remote_sa
;
569 struct nbr_params
*nbrp
;
574 nbr
->fd
= socket(nbr
->af
, SOCK_STREAM
, 0);
576 log_warn("%s: error while creating socket", __func__
);
579 sock_set_nonblock(nbr
->fd
);
581 nbrp
= nbr_params_find(leconf
, nbr
->id
);
582 if (nbrp
&& nbrp
->auth
.method
== AUTH_MD5SIG
) {
584 if (sysdep
.no_pfkey
|| sysdep
.no_md5sig
) {
585 log_warnx("md5sig configured but not available");
589 if (setsockopt(nbr
->fd
, IPPROTO_TCP
, TCP_MD5SIG
,
590 &opt
, sizeof(opt
)) == -1) {
591 log_warn("setsockopt md5sig");
596 sock_set_md5sig(nbr
->fd
, nbr
->af
, &nbr
->raddr
,
601 memcpy(&local_sa
, addr2sa(nbr
->af
, &nbr
->laddr
, 0), sizeof(local_sa
));
602 memcpy(&remote_sa
, addr2sa(nbr
->af
, &nbr
->raddr
, LDP_PORT
),
604 if (nbr
->af
== AF_INET6
&& nbr
->raddr_scope
)
605 addscope((struct sockaddr_in6
*)&remote_sa
, nbr
->raddr_scope
);
607 if (bind(nbr
->fd
, (struct sockaddr
*)&local_sa
,
608 sockaddr_len((struct sockaddr
*)&local_sa
)) == -1) {
609 log_warn("%s: error while binding socket to %s", __func__
,
610 log_sockaddr((struct sockaddr
*)&local_sa
));
615 if (nbr_gtsm_check(nbr
->fd
, nbr
, nbrp
)) {
621 * Send an extra hello to guarantee that the remote peer has formed
622 * an adjacency as well.
624 LIST_FOREACH(adj
, &nbr
->adj_list
, nbr_entry
)
625 send_hello(adj
->source
.type
, adj
->source
.link
.ia
,
628 if (connect(nbr
->fd
, (struct sockaddr
*)&remote_sa
,
629 sockaddr_len((struct sockaddr
*)&remote_sa
)) == -1) {
630 if (errno
== EINPROGRESS
) {
631 THREAD_WRITE_ON(master
, nbr
->ev_connect
, nbr_connect_cb
,
635 log_warn("%s: error while connecting to %s", __func__
,
636 log_sockaddr((struct sockaddr
*)&remote_sa
));
641 /* connection completed immediately */
642 nbr_fsm(nbr
, NBR_EVT_CONNECT_UP
);
648 nbr_gtsm_enabled(struct nbr
*nbr
, struct nbr_params
*nbrp
)
651 * RFC 6720 - Section 3:
652 * "This document allows for the implementation to provide an option to
653 * statically (e.g., via configuration) and/or dynamically override the
654 * default behavior and enable/disable GTSM on a per-peer basis".
656 if (nbrp
&& (nbrp
->flags
& F_NBRP_GTSM
))
657 return (nbrp
->gtsm_enabled
);
659 if ((ldp_af_conf_get(leconf
, nbr
->af
))->flags
& F_LDPD_AF_NO_GTSM
)
662 /* By default, GTSM support has to be negotiated for LDPv4 */
663 if (nbr
->af
== AF_INET
&& !(nbr
->flags
& F_NBR_GTSM_NEGOTIATED
))
670 nbr_gtsm_setup(int fd
, int af
, struct nbr_params
*nbrp
)
674 if (nbrp
&& (nbrp
->flags
& F_NBRP_GTSM_HOPS
))
675 ttl
= 256 - nbrp
->gtsm_hops
;
679 if (sock_set_ipv4_minttl(fd
, ttl
) == -1)
682 if (sock_set_ipv4_ucast_ttl(fd
, ttl
) == -1)
686 /* ignore any possible error */
687 sock_set_ipv6_minhopcount(fd
, ttl
);
689 if (sock_set_ipv6_ucast_hops(fd
, ttl
) == -1)
693 fatalx("nbr_gtsm_setup: unknown af");
700 nbr_gtsm_check(int fd
, struct nbr
*nbr
, struct nbr_params
*nbrp
)
702 if (!nbr_gtsm_enabled(nbr
, nbrp
)) {
705 sock_set_ipv4_ucast_ttl(fd
, -1);
709 * Send packets with a Hop Limit of 255 even when GSTM
710 * is disabled to guarantee interoperability.
712 sock_set_ipv6_ucast_hops(fd
, 255);
715 fatalx("nbr_gtsm_check: unknown af");
721 if (nbr_gtsm_setup(fd
, nbr
->af
, nbrp
) == -1) {
722 log_warnx("%s: error enabling GTSM for lsr-id %s", __func__
,
731 nbr_act_session_operational(struct nbr
*nbr
)
733 struct lde_nbr lde_nbr
;
735 nbr
->idtimer_cnt
= 0;
737 /* this is necessary to avoid ipc synchronization issues */
738 nbr_update_peerid(nbr
);
740 memset(&lde_nbr
, 0, sizeof(lde_nbr
));
741 lde_nbr
.id
= nbr
->id
;
742 lde_nbr
.v4_enabled
= nbr
->v4_enabled
;
743 lde_nbr
.v6_enabled
= nbr
->v6_enabled
;
744 return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP
, nbr
->peerid
, 0,
745 &lde_nbr
, sizeof(lde_nbr
)));
749 nbr_send_labelmappings(struct nbr
*nbr
)
751 ldpe_imsg_compose_lde(IMSG_LABEL_MAPPING_FULL
, nbr
->peerid
, 0,
756 nbr_params_new(struct in_addr lsr_id
)
758 struct nbr_params
*nbrp
;
760 if ((nbrp
= calloc(1, sizeof(*nbrp
))) == NULL
)
763 nbrp
->lsr_id
= lsr_id
;
764 nbrp
->auth
.method
= AUTH_NONE
;
770 nbr_params_find(struct ldpd_conf
*xconf
, struct in_addr lsr_id
)
772 struct nbr_params
*nbrp
;
774 LIST_FOREACH(nbrp
, &xconf
->nbrp_list
, entry
)
775 if (nbrp
->lsr_id
.s_addr
== lsr_id
.s_addr
)
782 nbr_get_keepalive(int af
, struct in_addr lsr_id
)
784 struct nbr_params
*nbrp
;
786 nbrp
= nbr_params_find(leconf
, lsr_id
);
787 if (nbrp
&& (nbrp
->flags
& F_NBRP_KEEPALIVE
))
788 return (nbrp
->keepalive
);
790 return ((ldp_af_conf_get(leconf
, af
))->keepalive
);
794 nbr_to_ctl(struct nbr
*nbr
)
796 static struct ctl_nbr nctl
;
801 nctl
.laddr
= nbr
->laddr
;
802 nctl
.lport
= nbr
->tcp
->lport
;
803 nctl
.raddr
= nbr
->raddr
;
804 nctl
.rport
= nbr
->tcp
->rport
;
805 nctl
.holdtime
= nbr
->keepalive
;
806 nctl
.nbr_state
= nbr
->state
;
808 gettimeofday(&now
, NULL
);
809 if (nbr
->state
== NBR_STA_OPER
) {
810 nctl
.uptime
= now
.tv_sec
- nbr
->uptime
;
818 nbr_clear_ctl(struct ctl_nbr
*nctl
)
822 RB_FOREACH(nbr
, nbr_addr_head
, &nbrs_by_addr
) {
823 if (ldp_addrisset(nctl
->af
, &nctl
->raddr
) &&
824 ldp_addrcmp(nctl
->af
, &nctl
->raddr
, &nbr
->raddr
))
827 log_debug("%s: neighbor %s manually cleared", __func__
,
828 log_addr(nbr
->af
, &nbr
->raddr
));
829 session_shutdown(nbr
, S_SHUTDOWN
, 0, 0);