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