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