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