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