]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/neighbor.c
tools: improve explanation of 'wrap' options
[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
8451921b
DL
29DEFINE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state),
30 (nbr, old_state));
f9a4d683 31
45926e58
RZ
32static __inline int nbr_id_compare(const struct nbr *, const struct nbr *);
33static __inline int nbr_addr_compare(const struct nbr *,
34 const struct nbr *);
35static __inline int nbr_pid_compare(const struct nbr *,
36 const struct nbr *);
8429abe0 37static void nbr_update_peerid(struct nbr *);
cc9f21da 38static void nbr_ktimer(struct thread *thread);
8429abe0 39static void nbr_start_ktimer(struct nbr *);
cc9f21da 40static void nbr_ktimeout(struct thread *thread);
8429abe0 41static void nbr_start_ktimeout(struct nbr *);
cc9f21da 42static void nbr_itimeout(struct thread *thread);
8429abe0 43static void nbr_start_itimeout(struct nbr *);
cc9f21da 44static void nbr_idtimer(struct thread *thread);
8429abe0
RW
45static int nbr_act_session_operational(struct nbr *);
46static void nbr_send_labelmappings(struct nbr *);
45926e58
RZ
47static __inline int nbr_params_compare(const struct nbr_params *,
48 const struct nbr_params *);
8429abe0
RW
49
50RB_GENERATE(nbr_id_head, nbr, id_tree, nbr_id_compare)
51RB_GENERATE(nbr_addr_head, nbr, addr_tree, nbr_addr_compare)
52RB_GENERATE(nbr_pid_head, nbr, pid_tree, nbr_pid_compare)
76c4abd1 53RB_GENERATE(nbrp_head, nbr_params, entry, nbr_params_compare)
8429abe0 54
2b64873d 55const struct {
8429abe0
RW
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
81const 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
93const 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
104struct nbr_id_head nbrs_by_id = RB_INITIALIZER(&nbrs_by_id);
105struct nbr_addr_head nbrs_by_addr = RB_INITIALIZER(&nbrs_by_addr);
106struct nbr_pid_head nbrs_by_pid = RB_INITIALIZER(&nbrs_by_pid);
107
108static __inline int
45926e58 109nbr_id_compare(const struct nbr *a, const struct nbr *b)
8429abe0
RW
110{
111 return (ntohl(a->id.s_addr) - ntohl(b->id.s_addr));
112}
113
114static __inline int
45926e58 115nbr_addr_compare(const struct nbr *a, const struct nbr *b)
8429abe0
RW
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
125static __inline int
45926e58 126nbr_pid_compare(const struct nbr *a, const struct nbr *b)
8429abe0
RW
127{
128 return (a->peerid - b->peerid);
129}
130
131int
132nbr_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. */
903a7226 149 log_warnx("%s: lsr-id %pI4, event %s not expected in state %s", __func__, &nbr->id,
8429abe0
RW
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) {
903a7226 158 log_debug("%s: event %s resulted in action %s and changing state for lsr-id %pI4 from %s to %s",
8429abe0
RW
159 __func__, nbr_event_names[event],
160 nbr_action_names[nbr_fsm_tbl[i].action],
903a7226 161 &nbr->id, nbr_state_name(old_state),
8429abe0
RW
162 nbr_state_name(nbr->state));
163
f9a4d683
KS
164 hook_call(ldp_nbr_state_change, nbr, old_state);
165
8429abe0
RW
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
222struct nbr *
223nbr_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
903a7226
MS
231 log_debug("%s: lsr-id %pI4 transport-address %s", __func__,
232 &id, log_addr(af, addr));
8429abe0
RW
233
234 if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
235 fatal(__func__);
236
45926e58 237 RB_INIT(nbr_adj_head, &nbr->adj_tree);
8429abe0
RW
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
057d48bd 252 RB_FOREACH(adj, global_adj_head, &global.adj_tree) {
8429abe0
RW
253 if (adj->lsr_id.s_addr == nbr->id.s_addr) {
254 adj->nbr = nbr;
057d48bd 255 RB_INSERT(nbr_adj_head, &nbr->adj_tree, adj);
8429abe0
RW
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
8429abe0 270 nbrp = nbr_params_find(leconf, nbr->id);
eac6e3f0 271 if (nbrp) {
0f7b5df9 272 nbr->auth.method = nbrp->auth.method;
eac6e3f0
RW
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 }
8429abe0
RW
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
292void
293nbr_del(struct nbr *nbr)
294{
6e4762e1
RW
295 struct adj *adj;
296
903a7226 297 log_debug("%s: lsr-id %pI4", __func__, &nbr->id);
8429abe0
RW
298
299 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
eac6e3f0 300#ifdef __OpenBSD__
8429abe0 301 pfkey_remove(nbr);
eac6e3f0
RW
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
0f7b5df9 307 nbr->auth.method = AUTH_NONE;
8429abe0
RW
308
309 if (nbr_pending_connect(nbr))
50478845 310 thread_cancel(&nbr->ev_connect);
8429abe0
RW
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
55cd0f61
DS
322 while (!RB_EMPTY(nbr_adj_head, &nbr->adj_tree)) {
323 adj = RB_ROOT(nbr_adj_head, &nbr->adj_tree);
324
6e4762e1
RW
325 adj->nbr = NULL;
326 RB_REMOVE(nbr_adj_head, &nbr->adj_tree, adj);
327 }
328
8429abe0
RW
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
337static void
338nbr_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
354struct nbr *
355nbr_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
f9a4d683
KS
362struct nbr *
363nbr_get_first_ldpid()
364{
365 return (RB_MIN(nbr_id_head, &nbrs_by_id));
366}
367
368struct nbr *
369nbr_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
8429abe0
RW
379struct nbr *
380nbr_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
388struct nbr *
389nbr_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
396int
397nbr_adj_count(struct nbr *nbr, int af)
398{
399 struct adj *adj;
400 int total = 0;
401
057d48bd 402 RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree)
8429abe0
RW
403 if (adj_get_af(adj) == af)
404 total++;
405
406 return (total);
407}
408
409int
410nbr_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
cc9f21da 422static void nbr_ktimer(struct thread *thread)
8429abe0 423{
eac6e3f0 424 struct nbr *nbr = THREAD_ARG(thread);
8429abe0 425
eac6e3f0 426 nbr->keepalive_timer = NULL;
8429abe0
RW
427 send_keepalive(nbr);
428 nbr_start_ktimer(nbr);
429}
430
431static void
432nbr_start_ktimer(struct nbr *nbr)
433{
eac6e3f0 434 int secs;
8429abe0
RW
435
436 /* send three keepalives per period */
eac6e3f0 437 secs = nbr->keepalive / KEEPALIVE_PER_PERIOD;
50478845 438 thread_cancel(&nbr->keepalive_timer);
66e78ae6
QY
439 nbr->keepalive_timer = NULL;
440 thread_add_timer(master, nbr_ktimer, nbr, secs, &nbr->keepalive_timer);
8429abe0
RW
441}
442
443void
444nbr_stop_ktimer(struct nbr *nbr)
445{
50478845 446 thread_cancel(&nbr->keepalive_timer);
8429abe0
RW
447}
448
449/* Keepalive timeout: if the nbr hasn't sent keepalive */
450
cc9f21da 451static void nbr_ktimeout(struct thread *thread)
8429abe0 452{
eac6e3f0
RW
453 struct nbr *nbr = THREAD_ARG(thread);
454
455 nbr->keepalive_timeout = NULL;
8429abe0 456
903a7226 457 log_debug("%s: lsr-id %pI4", __func__, &nbr->id);
8429abe0
RW
458
459 session_shutdown(nbr, S_KEEPALIVE_TMR, 0, 0);
460}
461
462static void
463nbr_start_ktimeout(struct nbr *nbr)
464{
50478845 465 thread_cancel(&nbr->keepalive_timeout);
66e78ae6
QY
466 nbr->keepalive_timeout = NULL;
467 thread_add_timer(master, nbr_ktimeout, nbr, nbr->keepalive,
468 &nbr->keepalive_timeout);
8429abe0
RW
469}
470
471void
472nbr_stop_ktimeout(struct nbr *nbr)
473{
50478845 474 thread_cancel(&nbr->keepalive_timeout);
8429abe0
RW
475}
476
477/* Session initialization timeout: if nbr got stuck in the initialization FSM */
478
cc9f21da 479static void nbr_itimeout(struct thread *thread)
8429abe0 480{
eac6e3f0 481 struct nbr *nbr = THREAD_ARG(thread);
8429abe0 482
903a7226 483 log_debug("%s: lsr-id %pI4", __func__, &nbr->id);
8429abe0
RW
484
485 nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
486}
487
488static void
489nbr_start_itimeout(struct nbr *nbr)
490{
eac6e3f0 491 int secs;
8429abe0 492
eac6e3f0 493 secs = INIT_FSM_TIMEOUT;
50478845 494 thread_cancel(&nbr->init_timeout);
66e78ae6
QY
495 nbr->init_timeout = NULL;
496 thread_add_timer(master, nbr_itimeout, nbr, secs, &nbr->init_timeout);
8429abe0
RW
497}
498
499void
500nbr_stop_itimeout(struct nbr *nbr)
501{
50478845 502 thread_cancel(&nbr->init_timeout);
8429abe0
RW
503}
504
505/* Init delay timer: timer to retry to iniziatize session */
506
cc9f21da 507static void nbr_idtimer(struct thread *thread)
8429abe0 508{
eac6e3f0
RW
509 struct nbr *nbr = THREAD_ARG(thread);
510
511 nbr->initdelay_timer = NULL;
8429abe0 512
903a7226 513 log_debug("%s: lsr-id %pI4", __func__, &nbr->id);
8429abe0
RW
514
515 nbr_establish_connection(nbr);
516}
517
518void
519nbr_start_idtimer(struct nbr *nbr)
520{
eac6e3f0 521 int secs;
8429abe0 522
eac6e3f0 523 secs = INIT_DELAY_TMR;
8429abe0
RW
524 switch(nbr->idtimer_cnt) {
525 default:
526 /* do not further increase the counter */
eac6e3f0 527 secs = MAX_DELAY_TMR;
8429abe0
RW
528 break;
529 case 2:
eac6e3f0 530 secs *= 2;
8429abe0
RW
531 /* FALLTHROUGH */
532 case 1:
eac6e3f0 533 secs *= 2;
8429abe0
RW
534 /* FALLTHROUGH */
535 case 0:
536 nbr->idtimer_cnt++;
537 break;
538 }
539
50478845 540 thread_cancel(&nbr->initdelay_timer);
66e78ae6
QY
541 nbr->initdelay_timer = NULL;
542 thread_add_timer(master, nbr_idtimer, nbr, secs,
543 &nbr->initdelay_timer);
8429abe0
RW
544}
545
546void
547nbr_stop_idtimer(struct nbr *nbr)
548{
50478845 549 thread_cancel(&nbr->initdelay_timer);
8429abe0
RW
550}
551
552int
553nbr_pending_idtimer(struct nbr *nbr)
554{
eac6e3f0 555 return (nbr->initdelay_timer != NULL);
8429abe0
RW
556}
557
558int
559nbr_pending_connect(struct nbr *nbr)
560{
eac6e3f0 561 return (nbr->ev_connect != NULL);
8429abe0
RW
562}
563
cc9f21da 564static void nbr_connect_cb(struct thread *thread)
8429abe0 565{
eac6e3f0 566 struct nbr *nbr = THREAD_ARG(thread);
8429abe0
RW
567 int error;
568 socklen_t len;
569
eac6e3f0
RW
570 nbr->ev_connect = NULL;
571
8429abe0
RW
572 len = sizeof(error);
573 if (getsockopt(nbr->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
574 log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__);
cc9f21da 575 return;
8429abe0
RW
576 }
577
578 if (error) {
579 close(nbr->fd);
580 errno = error;
581 log_debug("%s: error while connecting to %s: %s", __func__,
582 log_addr(nbr->af, &nbr->raddr), strerror(errno));
cc9f21da 583 return;
8429abe0
RW
584 }
585
586 nbr_fsm(nbr, NBR_EVT_CONNECT_UP);
587}
588
589int
590nbr_establish_connection(struct nbr *nbr)
591{
4149ef7c
A
592 union sockunion local_su;
593 union sockunion remote_su;
8429abe0
RW
594 struct adj *adj;
595 struct nbr_params *nbrp;
eac6e3f0 596#ifdef __OpenBSD__
8429abe0 597 int opt = 1;
eac6e3f0 598#endif
8429abe0 599
eac6e3f0 600 nbr->fd = socket(nbr->af, SOCK_STREAM, 0);
8429abe0
RW
601 if (nbr->fd == -1) {
602 log_warn("%s: error while creating socket", __func__);
603 return (-1);
604 }
eac6e3f0 605 sock_set_nonblock(nbr->fd);
8429abe0
RW
606
607 nbrp = nbr_params_find(leconf, nbr->id);
608 if (nbrp && nbrp->auth.method == AUTH_MD5SIG) {
eac6e3f0 609#ifdef __OpenBSD__
8429abe0
RW
610 if (sysdep.no_pfkey || sysdep.no_md5sig) {
611 log_warnx("md5sig configured but not available");
612 close(nbr->fd);
613 return (-1);
614 }
615 if (setsockopt(nbr->fd, IPPROTO_TCP, TCP_MD5SIG,
616 &opt, sizeof(opt)) == -1) {
617 log_warn("setsockopt md5sig");
618 close(nbr->fd);
619 return (-1);
620 }
eac6e3f0
RW
621#else
622 sock_set_md5sig(nbr->fd, nbr->af, &nbr->raddr,
623 nbrp->auth.md5key);
624#endif
8429abe0
RW
625 }
626
def23eb3
KS
627 if (nbr->af == AF_INET) {
628 if (sock_set_ipv4_tos(nbr->fd, IPTOS_PREC_INTERNETCONTROL) == -1)
903a7226
MS
629 log_warn("%s: lsr-id %pI4, sock_set_ipv4_tos error",
630 __func__, &nbr->id);
def23eb3
KS
631 } else if (nbr->af == AF_INET6) {
632 if (sock_set_ipv6_dscp(nbr->fd, IPTOS_PREC_INTERNETCONTROL) == -1)
903a7226
MS
633 log_warn("%s: lsr-id %pI4, sock_set_ipv6_dscp error",
634 __func__, &nbr->id);
def23eb3
KS
635 }
636
4149ef7c
A
637 addr2sa(nbr->af, &nbr->laddr, 0, &local_su);
638 addr2sa(nbr->af, &nbr->raddr, LDP_PORT, &remote_su);
8429abe0 639 if (nbr->af == AF_INET6 && nbr->raddr_scope)
4149ef7c 640 addscope(&remote_su.sin6, nbr->raddr_scope);
8429abe0 641
4149ef7c 642 if (bind(nbr->fd, &local_su.sa, sockaddr_len(&local_su.sa)) == -1) {
8429abe0 643 log_warn("%s: error while binding socket to %s", __func__,
4149ef7c 644 log_sockaddr(&local_su.sa));
8429abe0
RW
645 close(nbr->fd);
646 return (-1);
647 }
648
649 if (nbr_gtsm_check(nbr->fd, nbr, nbrp)) {
650 close(nbr->fd);
651 return (-1);
652 }
653
654 /*
655 * Send an extra hello to guarantee that the remote peer has formed
656 * an adjacency as well.
657 */
057d48bd 658 RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree)
8429abe0
RW
659 send_hello(adj->source.type, adj->source.link.ia,
660 adj->source.target);
661
4149ef7c
A
662 if (connect(nbr->fd, &remote_su.sa, sockaddr_len(&remote_su.sa))
663 == -1) {
8429abe0 664 if (errno == EINPROGRESS) {
ffa2c898
QY
665 thread_add_write(master, nbr_connect_cb, nbr, nbr->fd,
666 &nbr->ev_connect);
8429abe0
RW
667 return (0);
668 }
669 log_warn("%s: error while connecting to %s", __func__,
4149ef7c 670 log_sockaddr(&remote_su.sa));
8429abe0
RW
671 close(nbr->fd);
672 return (-1);
673 }
674
675 /* connection completed immediately */
676 nbr_fsm(nbr, NBR_EVT_CONNECT_UP);
677
678 return (0);
679}
680
681int
682nbr_gtsm_enabled(struct nbr *nbr, struct nbr_params *nbrp)
683{
684 /*
685 * RFC 6720 - Section 3:
686 * "This document allows for the implementation to provide an option to
687 * statically (e.g., via configuration) and/or dynamically override the
688 * default behavior and enable/disable GTSM on a per-peer basis".
689 */
690 if (nbrp && (nbrp->flags & F_NBRP_GTSM))
691 return (nbrp->gtsm_enabled);
692
693 if ((ldp_af_conf_get(leconf, nbr->af))->flags & F_LDPD_AF_NO_GTSM)
694 return (0);
695
696 /* By default, GTSM support has to be negotiated for LDPv4 */
697 if (nbr->af == AF_INET && !(nbr->flags & F_NBR_GTSM_NEGOTIATED))
698 return (0);
699
700 return (1);
701}
702
703int
704nbr_gtsm_setup(int fd, int af, struct nbr_params *nbrp)
705{
706 int ttl = 255;
707
708 if (nbrp && (nbrp->flags & F_NBRP_GTSM_HOPS))
709 ttl = 256 - nbrp->gtsm_hops;
710
711 switch (af) {
712 case AF_INET:
713 if (sock_set_ipv4_minttl(fd, ttl) == -1)
714 return (-1);
715 ttl = 255;
716 if (sock_set_ipv4_ucast_ttl(fd, ttl) == -1)
717 return (-1);
718 break;
719 case AF_INET6:
eac6e3f0
RW
720 /* ignore any possible error */
721 sock_set_ipv6_minhopcount(fd, ttl);
8429abe0
RW
722 ttl = 255;
723 if (sock_set_ipv6_ucast_hops(fd, ttl) == -1)
724 return (-1);
725 break;
726 default:
727 fatalx("nbr_gtsm_setup: unknown af");
728 }
729
730 return (0);
731}
732
733int
734nbr_gtsm_check(int fd, struct nbr *nbr, struct nbr_params *nbrp)
735{
736 if (!nbr_gtsm_enabled(nbr, nbrp)) {
737 switch (nbr->af) {
738 case AF_INET:
739 sock_set_ipv4_ucast_ttl(fd, -1);
740 break;
741 case AF_INET6:
742 /*
743 * Send packets with a Hop Limit of 255 even when GSTM
744 * is disabled to guarantee interoperability.
745 */
746 sock_set_ipv6_ucast_hops(fd, 255);
747 break;
748 default:
749 fatalx("nbr_gtsm_check: unknown af");
750 break;
751 }
752 return (0);
753 }
754
755 if (nbr_gtsm_setup(fd, nbr->af, nbrp) == -1) {
903a7226
MS
756 log_warnx("%s: error enabling GTSM for lsr-id %pI4", __func__,
757 &nbr->id);
8429abe0
RW
758 return (-1);
759 }
760
761 return (0);
762}
763
764static int
765nbr_act_session_operational(struct nbr *nbr)
766{
767 struct lde_nbr lde_nbr;
768
769 nbr->idtimer_cnt = 0;
770
771 /* this is necessary to avoid ipc synchronization issues */
772 nbr_update_peerid(nbr);
773
e1894ff7
KS
774 ldp_sync_fsm_nbr_event(nbr, LDP_SYNC_EVT_LDP_SYNC_START);
775
8429abe0
RW
776 memset(&lde_nbr, 0, sizeof(lde_nbr));
777 lde_nbr.id = nbr->id;
778 lde_nbr.v4_enabled = nbr->v4_enabled;
779 lde_nbr.v6_enabled = nbr->v6_enabled;
257799cd 780 lde_nbr.flags = nbr->flags;
8429abe0
RW
781 return (ldpe_imsg_compose_lde(IMSG_NEIGHBOR_UP, nbr->peerid, 0,
782 &lde_nbr, sizeof(lde_nbr)));
783}
784
785static void
786nbr_send_labelmappings(struct nbr *nbr)
787{
788 ldpe_imsg_compose_lde(IMSG_LABEL_MAPPING_FULL, nbr->peerid, 0,
789 NULL, 0);
790}
791
76c4abd1 792static __inline int
45926e58 793nbr_params_compare(const struct nbr_params *a, const struct nbr_params *b)
76c4abd1
RW
794{
795 return (ntohl(a->lsr_id.s_addr) - ntohl(b->lsr_id.s_addr));
796}
797
8429abe0
RW
798struct nbr_params *
799nbr_params_new(struct in_addr lsr_id)
800{
801 struct nbr_params *nbrp;
802
803 if ((nbrp = calloc(1, sizeof(*nbrp))) == NULL)
804 fatal(__func__);
805
806 nbrp->lsr_id = lsr_id;
807 nbrp->auth.method = AUTH_NONE;
808
809 return (nbrp);
810}
811
812struct nbr_params *
813nbr_params_find(struct ldpd_conf *xconf, struct in_addr lsr_id)
814{
76c4abd1
RW
815 struct nbr_params nbrp;
816 nbrp.lsr_id = lsr_id;
817 return (RB_FIND(nbrp_head, &xconf->nbrp_tree, &nbrp));
8429abe0
RW
818}
819
820uint16_t
821nbr_get_keepalive(int af, struct in_addr lsr_id)
822{
823 struct nbr_params *nbrp;
824
825 nbrp = nbr_params_find(leconf, lsr_id);
826 if (nbrp && (nbrp->flags & F_NBRP_KEEPALIVE))
827 return (nbrp->keepalive);
828
829 return ((ldp_af_conf_get(leconf, af))->keepalive);
830}
831
832struct ctl_nbr *
833nbr_to_ctl(struct nbr *nbr)
834{
835 static struct ctl_nbr nctl;
836 struct timeval now;
837
838 nctl.af = nbr->af;
839 nctl.id = nbr->id;
840 nctl.laddr = nbr->laddr;
f9a4d683 841 nctl.lport = nbr->tcp ? nbr->tcp->lport : 0;
8429abe0 842 nctl.raddr = nbr->raddr;
f9a4d683 843 nctl.rport = nbr->tcp ? nbr->tcp->rport : 0;
0f7b5df9 844 nctl.auth_method = nbr->auth.method;
eac6e3f0 845 nctl.holdtime = nbr->keepalive;
8429abe0 846 nctl.nbr_state = nbr->state;
0f7b5df9 847 nctl.stats = nbr->stats;
99cfc17f 848 nctl.flags = nbr->flags;
f9a4d683
KS
849 nctl.max_pdu_len = nbr->max_pdu_len;
850 if (nbr->keepalive_timer)
851 nctl.hold_time_remaining =
852 thread_timer_remain_second(nbr->keepalive_timer);
853 else
854 nctl.hold_time_remaining = 0;
8429abe0
RW
855
856 gettimeofday(&now, NULL);
857 if (nbr->state == NBR_STA_OPER) {
858 nctl.uptime = now.tv_sec - nbr->uptime;
859 } else
860 nctl.uptime = 0;
861
862 return (&nctl);
863}
864
865void
866nbr_clear_ctl(struct ctl_nbr *nctl)
867{
868 struct nbr *nbr;
869
870 RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) {
871 if (ldp_addrisset(nctl->af, &nctl->raddr) &&
872 ldp_addrcmp(nctl->af, &nctl->raddr, &nbr->raddr))
873 continue;
874
875 log_debug("%s: neighbor %s manually cleared", __func__,
876 log_addr(nbr->af, &nbr->raddr));
877 session_shutdown(nbr, S_SHUTDOWN, 0, 0);
878 }
879}