]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/neighbor.c
ldpd: use red-black trees to store 'tnbr' elements
[mirror_frr.git] / ldpd / neighbor.c
CommitLineData
8429abe0
RW
1/* $OpenBSD$ */
2
3/*
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>
8 *
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.
12 *
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.
20 */
21
eac6e3f0 22#include <zebra.h>
8429abe0
RW
23
24#include "ldpd.h"
25#include "ldpe.h"
26#include "lde.h"
27#include "log.h"
28
29static __inline int nbr_id_compare(struct nbr *, struct nbr *);
30static __inline int nbr_addr_compare(struct nbr *, struct nbr *);
31static __inline int nbr_pid_compare(struct nbr *, struct nbr *);
32static void nbr_update_peerid(struct nbr *);
eac6e3f0 33static int nbr_ktimer(struct thread *);
8429abe0 34static void nbr_start_ktimer(struct nbr *);
eac6e3f0 35static int nbr_ktimeout(struct thread *);
8429abe0 36static void nbr_start_ktimeout(struct nbr *);
eac6e3f0 37static int nbr_itimeout(struct thread *);
8429abe0 38static void nbr_start_itimeout(struct nbr *);
eac6e3f0 39static int nbr_idtimer(struct thread *);
8429abe0
RW
40static int nbr_act_session_operational(struct nbr *);
41static void nbr_send_labelmappings(struct nbr *);
42
43RB_GENERATE(nbr_id_head, nbr, id_tree, nbr_id_compare)
44RB_GENERATE(nbr_addr_head, nbr, addr_tree, nbr_addr_compare)
45RB_GENERATE(nbr_pid_head, nbr, pid_tree, nbr_pid_compare)
46
47struct {
48 int state;
49 enum nbr_event event;
50 enum nbr_action action;
51 int new_state;
52} nbr_fsm_tbl[] = {
53 /* current state event that happened action to take resulting state */
54/* Passive Role */
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},
58/* Active Role */
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},
67/* Session Close */
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},
71};
72
73const char * const nbr_event_names[] = {
74 "NOTHING",
75 "ADJACENCY MATCHED",
76 "CONNECTION UP",
77 "SESSION CLOSE",
78 "INIT RECEIVED",
79 "KEEPALIVE RECEIVED",
80 "PDU RECEIVED",
81 "PDU SENT",
82 "INIT SENT"
83};
84
85const char * const nbr_action_names[] = {
86 "NOTHING",
87 "RESET KEEPALIVE TIMEOUT",
88 "START NEIGHBOR SESSION",
89 "RESET KEEPALIVE TIMER",
90 "SETUP NEIGHBOR CONNECTION",
91 "SEND INIT AND KEEPALIVE",
92 "SEND KEEPALIVE",
93 "CLOSE SESSION"
94};
95
96struct nbr_id_head nbrs_by_id = RB_INITIALIZER(&nbrs_by_id);
97struct nbr_addr_head nbrs_by_addr = RB_INITIALIZER(&nbrs_by_addr);
98struct nbr_pid_head nbrs_by_pid = RB_INITIALIZER(&nbrs_by_pid);
99
100static __inline int
101nbr_id_compare(struct nbr *a, struct nbr *b)
102{
103 return (ntohl(a->id.s_addr) - ntohl(b->id.s_addr));
104}
105
106static __inline int
107nbr_addr_compare(struct nbr *a, struct nbr *b)
108{
109 if (a->af < b->af)
110 return (-1);
111 if (a->af > b->af)
112 return (1);
113
114 return (ldp_addrcmp(a->af, &a->raddr, &b->raddr));
115}
116
117static __inline int
118nbr_pid_compare(struct nbr *a, struct nbr *b)
119{
120 return (a->peerid - b->peerid);
121}
122
123int
124nbr_fsm(struct nbr *nbr, enum nbr_event event)
125{
126 struct timeval now;
127 int old_state;
128 int new_state = 0;
129 int i;
130
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;
136 break;
137 }
138
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));
144 return (0);
145 }
146
147 if (new_state != 0)
148 nbr->state = new_state;
149
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));
157
158 if (nbr->state == NBR_STA_OPER) {
159 gettimeofday(&now, NULL);
160 nbr->uptime = now.tv_sec;
161 }
162 }
163
164 if (nbr->state == NBR_STA_OPER || nbr->state == NBR_STA_PRESENT)
165 nbr_stop_itimeout(nbr);
166 else
167 nbr_start_itimeout(nbr);
168
169 switch (nbr_fsm_tbl[i].action) {
170 case NBR_ACT_RST_KTIMEOUT:
171 nbr_start_ktimeout(nbr);
172 break;
173 case NBR_ACT_RST_KTIMER:
174 nbr_start_ktimer(nbr);
175 break;
176 case NBR_ACT_SESSION_EST:
177 nbr_act_session_operational(nbr);
178 nbr_start_ktimer(nbr);
179 nbr_start_ktimeout(nbr);
180 if (nbr->v4_enabled)
181 send_address_all(nbr, AF_INET);
182 if (nbr->v6_enabled)
183 send_address_all(nbr, AF_INET6);
184 nbr_send_labelmappings(nbr);
185 break;
186 case NBR_ACT_CONNECT_SETUP:
187 nbr->tcp = tcp_new(nbr->fd, nbr);
188
189 /* trigger next state */
190 send_init(nbr);
191 nbr_fsm(nbr, NBR_EVT_INIT_SENT);
192 break;
193 case NBR_ACT_PASSIVE_INIT:
194 send_init(nbr);
195 send_keepalive(nbr);
196 break;
197 case NBR_ACT_KEEPALIVE_SEND:
198 nbr_start_ktimeout(nbr);
199 send_keepalive(nbr);
200 break;
201 case NBR_ACT_CLOSE_SESSION:
202 ldpe_imsg_compose_lde(IMSG_NEIGHBOR_DOWN, nbr->peerid, 0,
203 NULL, 0);
204 session_close(nbr);
205 break;
206 case NBR_ACT_NOTHING:
207 /* do nothing */
208 break;
209 }
210
211 return (0);
212}
213
214struct nbr *
215nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr,
216 uint32_t scope_id)
217{
218 struct nbr *nbr;
219 struct nbr_params *nbrp;
220 struct adj *adj;
221 struct pending_conn *pconn;
222
223 log_debug("%s: lsr-id %s transport-address %s", __func__,
224 inet_ntoa(id), log_addr(af, addr));
225
226 if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
227 fatal(__func__);
228
229 LIST_INIT(&nbr->adj_list);
230 nbr->state = NBR_STA_PRESENT;
231 nbr->peerid = 0;
232 nbr->af = af;
233 nbr->ds_tlv = ds_tlv;
234 if (af == AF_INET || ds_tlv)
235 nbr->v4_enabled = 1;
236 if (af == AF_INET6 || ds_tlv)
237 nbr->v6_enabled = 1;
238 nbr->id = id;
239 nbr->laddr = (ldp_af_conf_get(leconf, af))->trans_addr;
240 nbr->raddr = *addr;
241 nbr->raddr_scope = scope_id;
242 nbr->conf_seqnum = 0;
243
244 LIST_FOREACH(adj, &global.adj_list, global_entry) {
245 if (adj->lsr_id.s_addr == nbr->id.s_addr) {
246 adj->nbr = nbr;
247 LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry);
248 }
249 }
250
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");
255
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);
261
8429abe0 262 nbrp = nbr_params_find(leconf, nbr->id);
eac6e3f0
RW
263 if (nbrp) {
264#ifdef __OpenBSD__
265 if (pfkey_establish(nbr, nbrp) == -1)
266 fatalx("pfkey setup failed");
267#else
268 sock_set_md5sig(
269 (ldp_af_global_get(&global, nbr->af))->ldp_session_socket,
270 nbr->af, &nbr->raddr, nbrp->auth.md5key);
271#endif
272 }
8429abe0
RW
273
274 pconn = pending_conn_find(nbr->af, &nbr->raddr);
275 if (pconn) {
276 session_accept_nbr(nbr, pconn->fd);
277 pending_conn_del(pconn);
278 }
279
280 return (nbr);
281}
282
283void
284nbr_del(struct nbr *nbr)
285{
286 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
287
288 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
eac6e3f0 289#ifdef __OpenBSD__
8429abe0 290 pfkey_remove(nbr);
eac6e3f0
RW
291#else
292 sock_set_md5sig(
293 (ldp_af_global_get(&global, nbr->af))->ldp_session_socket,
294 nbr->af, &nbr->raddr, NULL);
295#endif
8429abe0
RW
296
297 if (nbr_pending_connect(nbr))
eac6e3f0 298 THREAD_WRITE_OFF(nbr->ev_connect);
8429abe0
RW
299 nbr_stop_ktimer(nbr);
300 nbr_stop_ktimeout(nbr);
301 nbr_stop_itimeout(nbr);
302 nbr_stop_idtimer(nbr);
303
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);
309
310 if (nbr->peerid)
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);
314
315 free(nbr);
316}
317
318static void
319nbr_update_peerid(struct nbr *nbr)
320{
321 static uint32_t peercnt = 1;
322
323 if (nbr->peerid)
324 RB_REMOVE(nbr_pid_head, &nbrs_by_pid, nbr);
325
326 /* get next unused peerid */
327 while (nbr_find_peerid(++peercnt))
328 ;
329 nbr->peerid = peercnt;
330
331 if (RB_INSERT(nbr_pid_head, &nbrs_by_pid, nbr) != NULL)
332 fatalx("nbr_update_peerid: RB_INSERT(nbrs_by_pid) failed");
333}
334
335struct nbr *
336nbr_find_ldpid(uint32_t lsr_id)
337{
338 struct nbr n;
339 n.id.s_addr = lsr_id;
340 return (RB_FIND(nbr_id_head, &nbrs_by_id, &n));
341}
342
343struct nbr *
344nbr_find_addr(int af, union ldpd_addr *addr)
345{
346 struct nbr n;
347 n.af = af;
348 n.raddr = *addr;
349 return (RB_FIND(nbr_addr_head, &nbrs_by_addr, &n));
350}
351
352struct nbr *
353nbr_find_peerid(uint32_t peerid)
354{
355 struct nbr n;
356 n.peerid = peerid;
357 return (RB_FIND(nbr_pid_head, &nbrs_by_pid, &n));
358}
359
360int
361nbr_adj_count(struct nbr *nbr, int af)
362{
363 struct adj *adj;
364 int total = 0;
365
366 LIST_FOREACH(adj, &nbr->adj_list, nbr_entry)
367 if (adj_get_af(adj) == af)
368 total++;
369
370 return (total);
371}
372
373int
374nbr_session_active_role(struct nbr *nbr)
375{
376 if (ldp_addrcmp(nbr->af, &nbr->laddr, &nbr->raddr) > 0)
377 return (1);
378
379 return (0);
380}
381
382/* timers */
383
384/* Keepalive timer: timer to send keepalive message to neighbors */
385
eac6e3f0
RW
386static int
387nbr_ktimer(struct thread *thread)
8429abe0 388{
eac6e3f0 389 struct nbr *nbr = THREAD_ARG(thread);
8429abe0 390
eac6e3f0 391 nbr->keepalive_timer = NULL;
8429abe0
RW
392 send_keepalive(nbr);
393 nbr_start_ktimer(nbr);
eac6e3f0
RW
394
395 return (0);
8429abe0
RW
396}
397
398static void
399nbr_start_ktimer(struct nbr *nbr)
400{
eac6e3f0 401 int secs;
8429abe0
RW
402
403 /* send three keepalives per period */
eac6e3f0
RW
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);
8429abe0
RW
407}
408
409void
410nbr_stop_ktimer(struct nbr *nbr)
411{
eac6e3f0 412 THREAD_TIMER_OFF(nbr->keepalive_timer);
8429abe0
RW
413}
414
415/* Keepalive timeout: if the nbr hasn't sent keepalive */
416
eac6e3f0
RW
417static int
418nbr_ktimeout(struct thread *thread)
8429abe0 419{
eac6e3f0
RW
420 struct nbr *nbr = THREAD_ARG(thread);
421
422 nbr->keepalive_timeout = NULL;
8429abe0
RW
423
424 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
425
426 session_shutdown(nbr, S_KEEPALIVE_TMR, 0, 0);
eac6e3f0
RW
427
428 return (0);
8429abe0
RW
429}
430
431static void
432nbr_start_ktimeout(struct nbr *nbr)
433{
eac6e3f0
RW
434 THREAD_TIMER_OFF(nbr->keepalive_timeout);
435 nbr->keepalive_timeout = thread_add_timer(master, nbr_ktimeout, nbr,
436 nbr->keepalive);
8429abe0
RW
437}
438
439void
440nbr_stop_ktimeout(struct nbr *nbr)
441{
eac6e3f0 442 THREAD_TIMER_OFF(nbr->keepalive_timeout);
8429abe0
RW
443}
444
445/* Session initialization timeout: if nbr got stuck in the initialization FSM */
446
eac6e3f0
RW
447static int
448nbr_itimeout(struct thread *thread)
8429abe0 449{
eac6e3f0 450 struct nbr *nbr = THREAD_ARG(thread);
8429abe0
RW
451
452 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
453
454 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
eac6e3f0
RW
455
456 return (0);
8429abe0
RW
457}
458
459static void
460nbr_start_itimeout(struct nbr *nbr)
461{
eac6e3f0 462 int secs;
8429abe0 463
eac6e3f0
RW
464 secs = INIT_FSM_TIMEOUT;
465 THREAD_TIMER_OFF(nbr->init_timeout);
466 nbr->init_timeout = thread_add_timer(master, nbr_itimeout, nbr, secs);
8429abe0
RW
467}
468
469void
470nbr_stop_itimeout(struct nbr *nbr)
471{
eac6e3f0 472 THREAD_TIMER_OFF(nbr->init_timeout);
8429abe0
RW
473}
474
475/* Init delay timer: timer to retry to iniziatize session */
476
eac6e3f0
RW
477static int
478nbr_idtimer(struct thread *thread)
8429abe0 479{
eac6e3f0
RW
480 struct nbr *nbr = THREAD_ARG(thread);
481
482 nbr->initdelay_timer = NULL;
8429abe0
RW
483
484 log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
485
486 nbr_establish_connection(nbr);
eac6e3f0
RW
487
488 return (0);
8429abe0
RW
489}
490
491void
492nbr_start_idtimer(struct nbr *nbr)
493{
eac6e3f0 494 int secs;
8429abe0 495
eac6e3f0 496 secs = INIT_DELAY_TMR;
8429abe0
RW
497 switch(nbr->idtimer_cnt) {
498 default:
499 /* do not further increase the counter */
eac6e3f0 500 secs = MAX_DELAY_TMR;
8429abe0
RW
501 break;
502 case 2:
eac6e3f0 503 secs *= 2;
8429abe0
RW
504 /* FALLTHROUGH */
505 case 1:
eac6e3f0 506 secs *= 2;
8429abe0
RW
507 /* FALLTHROUGH */
508 case 0:
509 nbr->idtimer_cnt++;
510 break;
511 }
512
eac6e3f0
RW
513 THREAD_TIMER_OFF(nbr->initdelay_timer);
514 nbr->initdelay_timer = thread_add_timer(master, nbr_idtimer, nbr, secs);
8429abe0
RW
515}
516
517void
518nbr_stop_idtimer(struct nbr *nbr)
519{
eac6e3f0 520 THREAD_TIMER_OFF(nbr->initdelay_timer);
8429abe0
RW
521}
522
523int
524nbr_pending_idtimer(struct nbr *nbr)
525{
eac6e3f0 526 return (nbr->initdelay_timer != NULL);
8429abe0
RW
527}
528
529int
530nbr_pending_connect(struct nbr *nbr)
531{
eac6e3f0 532 return (nbr->ev_connect != NULL);
8429abe0
RW
533}
534
eac6e3f0
RW
535static int
536nbr_connect_cb(struct thread *thread)
8429abe0 537{
eac6e3f0 538 struct nbr *nbr = THREAD_ARG(thread);
8429abe0
RW
539 int error;
540 socklen_t len;
541
eac6e3f0
RW
542 nbr->ev_connect = NULL;
543
8429abe0
RW
544 len = sizeof(error);
545 if (getsockopt(nbr->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
546 log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__);
eac6e3f0 547 return (0);
8429abe0
RW
548 }
549
550 if (error) {
551 close(nbr->fd);
552 errno = error;
553 log_debug("%s: error while connecting to %s: %s", __func__,
554 log_addr(nbr->af, &nbr->raddr), strerror(errno));
eac6e3f0 555 return (0);
8429abe0
RW
556 }
557
558 nbr_fsm(nbr, NBR_EVT_CONNECT_UP);
eac6e3f0
RW
559
560 return (0);
8429abe0
RW
561}
562
563int
564nbr_establish_connection(struct nbr *nbr)
565{
566 struct sockaddr_storage local_sa;
567 struct sockaddr_storage remote_sa;
568 struct adj *adj;
569 struct nbr_params *nbrp;
eac6e3f0 570#ifdef __OpenBSD__
8429abe0 571 int opt = 1;
eac6e3f0 572#endif
8429abe0 573
eac6e3f0 574 nbr->fd = socket(nbr->af, SOCK_STREAM, 0);
8429abe0
RW
575 if (nbr->fd == -1) {
576 log_warn("%s: error while creating socket", __func__);
577 return (-1);
578 }
eac6e3f0 579 sock_set_nonblock(nbr->fd);
8429abe0
RW
580
581 nbrp = nbr_params_find(leconf, nbr->id);
582 if (nbrp && nbrp->auth.method == AUTH_MD5SIG) {
eac6e3f0 583#ifdef __OpenBSD__
8429abe0
RW
584 if (sysdep.no_pfkey || sysdep.no_md5sig) {
585 log_warnx("md5sig configured but not available");
586 close(nbr->fd);
587 return (-1);
588 }
589 if (setsockopt(nbr->fd, IPPROTO_TCP, TCP_MD5SIG,
590 &opt, sizeof(opt)) == -1) {
591 log_warn("setsockopt md5sig");
592 close(nbr->fd);
593 return (-1);
594 }
eac6e3f0
RW
595#else
596 sock_set_md5sig(nbr->fd, nbr->af, &nbr->raddr,
597 nbrp->auth.md5key);
598#endif
8429abe0
RW
599 }
600
601 memcpy(&local_sa, addr2sa(nbr->af, &nbr->laddr, 0), sizeof(local_sa));
602 memcpy(&remote_sa, addr2sa(nbr->af, &nbr->raddr, LDP_PORT),
603 sizeof(local_sa));
604 if (nbr->af == AF_INET6 && nbr->raddr_scope)
605 addscope((struct sockaddr_in6 *)&remote_sa, nbr->raddr_scope);
606
607 if (bind(nbr->fd, (struct sockaddr *)&local_sa,
eac6e3f0 608 sockaddr_len((struct sockaddr *)&local_sa)) == -1) {
8429abe0
RW
609 log_warn("%s: error while binding socket to %s", __func__,
610 log_sockaddr((struct sockaddr *)&local_sa));
611 close(nbr->fd);
612 return (-1);
613 }
614
615 if (nbr_gtsm_check(nbr->fd, nbr, nbrp)) {
616 close(nbr->fd);
617 return (-1);
618 }
619
620 /*
621 * Send an extra hello to guarantee that the remote peer has formed
622 * an adjacency as well.
623 */
624 LIST_FOREACH(adj, &nbr->adj_list, nbr_entry)
625 send_hello(adj->source.type, adj->source.link.ia,
626 adj->source.target);
627
628 if (connect(nbr->fd, (struct sockaddr *)&remote_sa,
eac6e3f0 629 sockaddr_len((struct sockaddr *)&remote_sa)) == -1) {
8429abe0 630 if (errno == EINPROGRESS) {
eac6e3f0
RW
631 THREAD_WRITE_ON(master, nbr->ev_connect, nbr_connect_cb,
632 nbr, nbr->fd);
8429abe0
RW
633 return (0);
634 }
635 log_warn("%s: error while connecting to %s", __func__,
636 log_sockaddr((struct sockaddr *)&remote_sa));
637 close(nbr->fd);
638 return (-1);
639 }
640
641 /* connection completed immediately */
642 nbr_fsm(nbr, NBR_EVT_CONNECT_UP);
643
644 return (0);
645}
646
647int
648nbr_gtsm_enabled(struct nbr *nbr, struct nbr_params *nbrp)
649{
650 /*
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".
655 */
656 if (nbrp && (nbrp->flags & F_NBRP_GTSM))
657 return (nbrp->gtsm_enabled);
658
659 if ((ldp_af_conf_get(leconf, nbr->af))->flags & F_LDPD_AF_NO_GTSM)
660 return (0);
661
662 /* By default, GTSM support has to be negotiated for LDPv4 */
663 if (nbr->af == AF_INET && !(nbr->flags & F_NBR_GTSM_NEGOTIATED))
664 return (0);
665
666 return (1);
667}
668
669int
670nbr_gtsm_setup(int fd, int af, struct nbr_params *nbrp)
671{
672 int ttl = 255;
673
674 if (nbrp && (nbrp->flags & F_NBRP_GTSM_HOPS))
675 ttl = 256 - nbrp->gtsm_hops;
676
677 switch (af) {
678 case AF_INET:
679 if (sock_set_ipv4_minttl(fd, ttl) == -1)
680 return (-1);
681 ttl = 255;
682 if (sock_set_ipv4_ucast_ttl(fd, ttl) == -1)
683 return (-1);
684 break;
685 case AF_INET6:
eac6e3f0
RW
686 /* ignore any possible error */
687 sock_set_ipv6_minhopcount(fd, ttl);
8429abe0
RW
688 ttl = 255;
689 if (sock_set_ipv6_ucast_hops(fd, ttl) == -1)
690 return (-1);
691 break;
692 default:
693 fatalx("nbr_gtsm_setup: unknown af");
694 }
695
696 return (0);
697}
698
699int
700nbr_gtsm_check(int fd, struct nbr *nbr, struct nbr_params *nbrp)
701{
702 if (!nbr_gtsm_enabled(nbr, nbrp)) {
703 switch (nbr->af) {
704 case AF_INET:
705 sock_set_ipv4_ucast_ttl(fd, -1);
706 break;
707 case AF_INET6:
708 /*
709 * Send packets with a Hop Limit of 255 even when GSTM
710 * is disabled to guarantee interoperability.
711 */
712 sock_set_ipv6_ucast_hops(fd, 255);
713 break;
714 default:
715 fatalx("nbr_gtsm_check: unknown af");
716 break;
717 }
718 return (0);
719 }
720
721 if (nbr_gtsm_setup(fd, nbr->af, nbrp) == -1) {
722 log_warnx("%s: error enabling GTSM for lsr-id %s", __func__,
723 inet_ntoa(nbr->id));
724 return (-1);
725 }
726
727 return (0);
728}
729
730static int
731nbr_act_session_operational(struct nbr *nbr)
732{
733 struct lde_nbr lde_nbr;
734
735 nbr->idtimer_cnt = 0;
736
737 /* this is necessary to avoid ipc synchronization issues */
738 nbr_update_peerid(nbr);
739
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)));
746}
747
748static void
749nbr_send_labelmappings(struct nbr *nbr)
750{
751 ldpe_imsg_compose_lde(IMSG_LABEL_MAPPING_FULL, nbr->peerid, 0,
752 NULL, 0);
753}
754
755struct nbr_params *
756nbr_params_new(struct in_addr lsr_id)
757{
758 struct nbr_params *nbrp;
759
760 if ((nbrp = calloc(1, sizeof(*nbrp))) == NULL)
761 fatal(__func__);
762
763 nbrp->lsr_id = lsr_id;
764 nbrp->auth.method = AUTH_NONE;
765
766 return (nbrp);
767}
768
769struct nbr_params *
770nbr_params_find(struct ldpd_conf *xconf, struct in_addr lsr_id)
771{
772 struct nbr_params *nbrp;
773
774 LIST_FOREACH(nbrp, &xconf->nbrp_list, entry)
775 if (nbrp->lsr_id.s_addr == lsr_id.s_addr)
776 return (nbrp);
777
778 return (NULL);
779}
780
781uint16_t
782nbr_get_keepalive(int af, struct in_addr lsr_id)
783{
784 struct nbr_params *nbrp;
785
786 nbrp = nbr_params_find(leconf, lsr_id);
787 if (nbrp && (nbrp->flags & F_NBRP_KEEPALIVE))
788 return (nbrp->keepalive);
789
790 return ((ldp_af_conf_get(leconf, af))->keepalive);
791}
792
793struct ctl_nbr *
794nbr_to_ctl(struct nbr *nbr)
795{
796 static struct ctl_nbr nctl;
797 struct timeval now;
798
799 nctl.af = nbr->af;
800 nctl.id = nbr->id;
801 nctl.laddr = nbr->laddr;
eac6e3f0 802 nctl.lport = nbr->tcp->lport;
8429abe0 803 nctl.raddr = nbr->raddr;
eac6e3f0
RW
804 nctl.rport = nbr->tcp->rport;
805 nctl.holdtime = nbr->keepalive;
8429abe0
RW
806 nctl.nbr_state = nbr->state;
807
808 gettimeofday(&now, NULL);
809 if (nbr->state == NBR_STA_OPER) {
810 nctl.uptime = now.tv_sec - nbr->uptime;
811 } else
812 nctl.uptime = 0;
813
814 return (&nctl);
815}
816
817void
818nbr_clear_ctl(struct ctl_nbr *nctl)
819{
820 struct nbr *nbr;
821
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))
825 continue;
826
827 log_debug("%s: neighbor %s manually cleared", __func__,
828 log_addr(nbr->af, &nbr->raddr));
829 session_shutdown(nbr, S_SHUTDOWN, 0, 0);
830 }
831}