]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/interface.c
pimd: fix mtracebis tool warning
[mirror_frr.git] / ldpd / interface.c
1 /* $OpenBSD$ */
2
3 /*
4 * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2004, 2005, 2008 Esben Norby <norby@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 #include <zebra.h>
22
23 #include "ldpd.h"
24 #include "ldpe.h"
25 #include "log.h"
26 #include "ldp_debug.h"
27
28 #include "sockopt.h"
29
30 static __inline int iface_compare(const struct iface *, const struct iface *);
31 static struct if_addr *if_addr_new(struct kaddr *);
32 static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *);
33 static int if_start(struct iface *, int);
34 static int if_reset(struct iface *, int);
35 static void if_update_af(struct iface_af *);
36 static void if_hello_timer(struct thread *thread);
37 static void if_start_hello_timer(struct iface_af *);
38 static void if_stop_hello_timer(struct iface_af *);
39 static int if_join_ipv4_group(struct iface *, struct in_addr *);
40 static int if_leave_ipv4_group(struct iface *, struct in_addr *);
41 static int if_join_ipv6_group(struct iface *, struct in6_addr *);
42 static int if_leave_ipv6_group(struct iface *, struct in6_addr *);
43
44 static int ldp_sync_fsm_init(struct iface *iface, int state);
45 static int ldp_sync_act_iface_start_sync(struct iface *iface);
46 static void iface_wait_for_ldp_sync_timer(struct thread *thread);
47 static void start_wait_for_ldp_sync_timer(struct iface *iface);
48 static void stop_wait_for_ldp_sync_timer(struct iface *iface);
49 static int ldp_sync_act_ldp_start_sync(struct iface *iface);
50 static int ldp_sync_act_ldp_complete_sync(struct iface *iface);
51 static int iface_to_oper_nbr_count(struct iface *iface, unsigned int type);
52 static void ldp_sync_get_peer_ldp_id(struct iface *iface,
53 struct in_addr *peer_ldp_id);
54
55 RB_GENERATE(iface_head, iface, entry, iface_compare)
56
57 static __inline int
58 iface_compare(const struct iface *a, const struct iface *b)
59 {
60 return if_cmp_name_func(a->name, b->name);
61 }
62
63 struct iface *
64 if_new(const char *name)
65 {
66 struct iface *iface;
67
68 if ((iface = calloc(1, sizeof(*iface))) == NULL)
69 fatal("if_new: calloc");
70
71 strlcpy(iface->name, name, sizeof(iface->name));
72
73 /* ipv4 */
74 iface->ipv4.af = AF_INET;
75 iface->ipv4.iface = iface;
76 iface->ipv4.enabled = 0;
77
78 /* ipv6 */
79 iface->ipv6.af = AF_INET6;
80 iface->ipv6.iface = iface;
81 iface->ipv6.enabled = 0;
82
83 return (iface);
84 }
85
86 void
87 ldpe_if_init(struct iface *iface)
88 {
89 log_debug("%s: interface %s", __func__, iface->name);
90
91 LIST_INIT(&iface->addr_list);
92
93 /* ipv4 */
94 iface->ipv4.iface = iface;
95 iface->ipv4.state = IF_STA_DOWN;
96 RB_INIT(ia_adj_head, &iface->ipv4.adj_tree);
97
98 /* ipv6 */
99 iface->ipv6.iface = iface;
100 iface->ipv6.state = IF_STA_DOWN;
101 RB_INIT(ia_adj_head, &iface->ipv6.adj_tree);
102
103 /* LGP IGP Sync */
104 ldp_sync_fsm_init(iface, LDP_SYNC_STA_NOT_ACH);
105 }
106
107 void
108 ldpe_if_exit(struct iface *iface)
109 {
110 struct if_addr *if_addr;
111
112 log_debug("%s: interface %s", __func__, iface->name);
113
114 ldp_sync_fsm(iface, LDP_SYNC_EVT_CONFIG_LDP_OFF);
115
116 if (iface->ipv4.state == IF_STA_ACTIVE)
117 if_reset(iface, AF_INET);
118 if (iface->ipv6.state == IF_STA_ACTIVE)
119 if_reset(iface, AF_INET6);
120
121 while ((if_addr = LIST_FIRST(&iface->addr_list)) != NULL) {
122 LIST_REMOVE(if_addr, entry);
123 assert(if_addr != LIST_FIRST(&iface->addr_list));
124 free(if_addr);
125 }
126 }
127
128 struct iface *
129 if_lookup(struct ldpd_conf *xconf, ifindex_t ifindex)
130 {
131 struct iface *iface;
132
133 RB_FOREACH(iface, iface_head, &xconf->iface_tree)
134 if (iface->ifindex == ifindex)
135 return (iface);
136
137 return (NULL);
138 }
139
140 struct iface *
141 if_lookup_name(struct ldpd_conf *xconf, const char *ifname)
142 {
143 struct iface iface;
144 strlcpy(iface.name, ifname, sizeof(iface.name));
145 return (RB_FIND(iface_head, &xconf->iface_tree, &iface));
146 }
147
148 void
149 if_update_info(struct iface *iface, struct kif *kif)
150 {
151 /* get type */
152 if (kif->flags & IFF_POINTOPOINT)
153 iface->type = IF_TYPE_POINTOPOINT;
154 if (kif->flags & IFF_BROADCAST &&
155 kif->flags & IFF_MULTICAST)
156 iface->type = IF_TYPE_BROADCAST;
157
158 if (ldpd_process == PROC_LDP_ENGINE && iface->operative &&
159 !kif->operative)
160 ldp_sync_fsm(iface, LDP_SYNC_EVT_IFACE_SHUTDOWN);
161
162 /* get index and flags */
163 iface->ifindex = kif->ifindex;
164 iface->operative = kif->operative;
165 }
166
167 struct iface_af *
168 iface_af_get(struct iface *iface, int af)
169 {
170 switch (af) {
171 case AF_INET:
172 return (&iface->ipv4);
173 case AF_INET6:
174 return (&iface->ipv6);
175 default:
176 fatalx("iface_af_get: unknown af");
177 }
178 }
179
180 static struct if_addr *
181 if_addr_new(struct kaddr *ka)
182 {
183 struct if_addr *if_addr;
184
185 if ((if_addr = calloc(1, sizeof(*if_addr))) == NULL)
186 fatal(__func__);
187
188 if_addr->af = ka->af;
189 if_addr->addr = ka->addr;
190 if_addr->prefixlen = ka->prefixlen;
191 if_addr->dstbrd = ka->dstbrd;
192
193 return (if_addr);
194 }
195
196 static struct if_addr *
197 if_addr_lookup(struct if_addr_head *addr_list, struct kaddr *ka)
198 {
199 struct if_addr *if_addr;
200 int af = ka->af;
201
202 LIST_FOREACH(if_addr, addr_list, entry)
203 if (!ldp_addrcmp(af, &if_addr->addr, &ka->addr) &&
204 if_addr->prefixlen == ka->prefixlen &&
205 !ldp_addrcmp(af, &if_addr->dstbrd, &ka->dstbrd))
206 return (if_addr);
207
208 return (NULL);
209 }
210
211 void
212 if_addr_add(struct kaddr *ka)
213 {
214 struct iface *iface;
215 struct if_addr *if_addr;
216 struct nbr *nbr;
217
218 if (if_addr_lookup(&global.addr_list, ka) == NULL) {
219 if_addr = if_addr_new(ka);
220
221 LIST_INSERT_HEAD(&global.addr_list, if_addr, entry);
222 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
223 if (nbr->state != NBR_STA_OPER)
224 continue;
225 if (if_addr->af == AF_INET && !nbr->v4_enabled)
226 continue;
227 if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
228 continue;
229
230 send_address_single(nbr, if_addr, 0);
231 }
232 }
233
234 iface = if_lookup_name(leconf, ka->ifname);
235 if (iface) {
236 if (ka->af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&ka->addr.v6))
237 iface->linklocal = ka->addr.v6;
238
239 if (if_addr_lookup(&iface->addr_list, ka) == NULL) {
240 if_addr = if_addr_new(ka);
241 LIST_INSERT_HEAD(&iface->addr_list, if_addr, entry);
242 ldp_if_update(iface, if_addr->af);
243 }
244 }
245 }
246
247 void
248 if_addr_del(struct kaddr *ka)
249 {
250 struct iface *iface;
251 struct if_addr *if_addr;
252 struct nbr *nbr;
253
254 iface = if_lookup_name(leconf, ka->ifname);
255 if (iface) {
256 if (ka->af == AF_INET6 &&
257 IN6_ARE_ADDR_EQUAL(&iface->linklocal, &ka->addr.v6))
258 memset(&iface->linklocal, 0, sizeof(iface->linklocal));
259
260 if_addr = if_addr_lookup(&iface->addr_list, ka);
261 if (if_addr) {
262 LIST_REMOVE(if_addr, entry);
263 ldp_if_update(iface, if_addr->af);
264 free(if_addr);
265 }
266 }
267
268 if_addr = if_addr_lookup(&global.addr_list, ka);
269 if (if_addr) {
270 RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) {
271 if (nbr->state != NBR_STA_OPER)
272 continue;
273 if (if_addr->af == AF_INET && !nbr->v4_enabled)
274 continue;
275 if (if_addr->af == AF_INET6 && !nbr->v6_enabled)
276 continue;
277 send_address_single(nbr, if_addr, 1);
278 }
279 LIST_REMOVE(if_addr, entry);
280 free(if_addr);
281 }
282 }
283
284 static int
285 if_start(struct iface *iface, int af)
286 {
287 struct iface_af *ia;
288 struct timeval now;
289
290 log_debug("%s: %s address-family %s", __func__, iface->name,
291 af_name(af));
292
293 ia = iface_af_get(iface, af);
294
295 gettimeofday(&now, NULL);
296 ia->uptime = now.tv_sec;
297
298 switch (af) {
299 case AF_INET:
300 if (if_join_ipv4_group(iface, &global.mcast_addr_v4))
301 return (-1);
302 break;
303 case AF_INET6:
304 if (if_join_ipv6_group(iface, &global.mcast_addr_v6))
305 return (-1);
306 break;
307 default:
308 fatalx("if_start: unknown af");
309 }
310
311 send_hello(HELLO_LINK, ia, NULL);
312 if_start_hello_timer(ia);
313 ia->state = IF_STA_ACTIVE;
314
315 return (0);
316 }
317
318 static int
319 if_reset(struct iface *iface, int af)
320 {
321 struct iface_af *ia;
322 struct adj *adj;
323
324 log_debug("%s: %s address-family %s", __func__, iface->name,
325 af_name(af));
326
327 ia = iface_af_get(iface, af);
328 if_stop_hello_timer(ia);
329
330 while (!RB_EMPTY(ia_adj_head, &ia->adj_tree)) {
331 adj = RB_ROOT(ia_adj_head, &ia->adj_tree);
332
333 adj_del(adj, S_SHUTDOWN);
334 }
335
336 /* try to cleanup */
337 switch (af) {
338 case AF_INET:
339 if (global.ipv4.ldp_disc_socket != -1)
340 if_leave_ipv4_group(iface, &global.mcast_addr_v4);
341 break;
342 case AF_INET6:
343 if (global.ipv6.ldp_disc_socket != -1)
344 if_leave_ipv6_group(iface, &global.mcast_addr_v6);
345 break;
346 default:
347 fatalx("if_reset: unknown af");
348 }
349
350 ia->state = IF_STA_DOWN;
351
352 return (0);
353 }
354
355 static void
356 if_update_af(struct iface_af *ia)
357 {
358 int addr_ok = 0, socket_ok, rtr_id_ok;
359 struct if_addr *if_addr;
360
361 switch (ia->af) {
362 case AF_INET:
363 /*
364 * NOTE: for LDPv4, each interface should have at least one
365 * valid IP address otherwise they can not be enabled.
366 */
367 LIST_FOREACH(if_addr, &ia->iface->addr_list, entry) {
368 if (if_addr->af == AF_INET) {
369 addr_ok = 1;
370 break;
371 }
372 }
373 break;
374 case AF_INET6:
375 /* for IPv6 the link-local address is enough. */
376 if (IN6_IS_ADDR_LINKLOCAL(&ia->iface->linklocal))
377 addr_ok = 1;
378 break;
379 default:
380 fatalx("if_update_af: unknown af");
381 }
382
383 if ((ldp_af_global_get(&global, ia->af))->ldp_disc_socket != -1)
384 socket_ok = 1;
385 else
386 socket_ok = 0;
387
388 if (ldp_rtr_id_get(leconf) != INADDR_ANY)
389 rtr_id_ok = 1;
390 else
391 rtr_id_ok = 0;
392
393 if (ia->state == IF_STA_DOWN) {
394 if (!ia->enabled || !ia->iface->operative || !addr_ok ||
395 !socket_ok || !rtr_id_ok)
396 return;
397
398 if_start(ia->iface, ia->af);
399 } else if (ia->state == IF_STA_ACTIVE) {
400 if (ia->enabled && ia->iface->operative && addr_ok &&
401 socket_ok && rtr_id_ok)
402 return;
403
404 if_reset(ia->iface, ia->af);
405 }
406 }
407
408 void
409 ldp_if_update(struct iface *iface, int af)
410 {
411 if (af == AF_INET || af == AF_UNSPEC)
412 if_update_af(&iface->ipv4);
413 if (af == AF_INET6 || af == AF_UNSPEC)
414 if_update_af(&iface->ipv6);
415 }
416
417 void
418 if_update_all(int af)
419 {
420 struct iface *iface;
421
422 RB_FOREACH(iface, iface_head, &leconf->iface_tree)
423 ldp_if_update(iface, af);
424 }
425
426 uint16_t
427 if_get_hello_holdtime(struct iface_af *ia)
428 {
429 if (ia->hello_holdtime != 0)
430 return (ia->hello_holdtime);
431
432 if ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime != 0)
433 return ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime);
434
435 return (leconf->lhello_holdtime);
436 }
437
438 uint16_t
439 if_get_hello_interval(struct iface_af *ia)
440 {
441 if (ia->hello_interval != 0)
442 return (ia->hello_interval);
443
444 if ((ldp_af_conf_get(leconf, ia->af))->lhello_interval != 0)
445 return ((ldp_af_conf_get(leconf, ia->af))->lhello_interval);
446
447 return (leconf->lhello_interval);
448 }
449
450 uint16_t
451 if_get_wait_for_sync_interval(void)
452 {
453 return (leconf->wait_for_sync_interval);
454 }
455
456 /* timers */
457 /* ARGSUSED */
458 static void if_hello_timer(struct thread *thread)
459 {
460 struct iface_af *ia = THREAD_ARG(thread);
461
462 ia->hello_timer = NULL;
463 send_hello(HELLO_LINK, ia, NULL);
464 if_start_hello_timer(ia);
465 }
466
467 static void
468 if_start_hello_timer(struct iface_af *ia)
469 {
470 THREAD_OFF(ia->hello_timer);
471 thread_add_timer(master, if_hello_timer, ia, if_get_hello_interval(ia),
472 &ia->hello_timer);
473 }
474
475 static void
476 if_stop_hello_timer(struct iface_af *ia)
477 {
478 THREAD_OFF(ia->hello_timer);
479 }
480
481 struct ctl_iface *
482 if_to_ctl(struct iface_af *ia)
483 {
484 static struct ctl_iface ictl;
485 struct timeval now;
486 struct adj *adj;
487
488 ictl.af = ia->af;
489 memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
490 ictl.ifindex = ia->iface->ifindex;
491 ictl.state = ia->state;
492 ictl.type = ia->iface->type;
493 ictl.hello_holdtime = if_get_hello_holdtime(ia);
494 ictl.hello_interval = if_get_hello_interval(ia);
495
496 gettimeofday(&now, NULL);
497 if (ia->state != IF_STA_DOWN &&
498 ia->uptime != 0) {
499 ictl.uptime = now.tv_sec - ia->uptime;
500 } else
501 ictl.uptime = 0;
502
503 ictl.adj_cnt = 0;
504 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
505 ictl.adj_cnt++;
506
507 return (&ictl);
508 }
509
510 static void
511 ldp_sync_get_peer_ldp_id(struct iface *iface, struct in_addr *peer_ldp_id)
512 {
513 struct iface_af *ia;
514 struct adj *adj;
515
516 if (iface->ipv4.state == IF_STA_ACTIVE) {
517 ia = iface_af_get(iface, AF_INET);
518 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
519 if (adj->nbr && adj->nbr->state == NBR_STA_OPER) {
520 *peer_ldp_id = adj->nbr->id;
521 return;
522 }
523 }
524
525 if (iface->ipv6.state == IF_STA_ACTIVE) {
526 ia = iface_af_get(iface, AF_INET6);
527 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
528 if (adj->nbr && adj->nbr->state == NBR_STA_OPER) {
529 *peer_ldp_id = adj->nbr->id;
530 return;
531 }
532 }
533 }
534
535 struct ctl_ldp_sync *
536 ldp_sync_to_ctl(struct iface *iface)
537 {
538 static struct ctl_ldp_sync ictl;
539
540 memcpy(ictl.name, iface->name, sizeof(ictl.name));
541 ictl.ifindex = iface->ifindex;
542 ictl.in_sync = (iface->ldp_sync.state == LDP_SYNC_STA_ACH);
543 ictl.wait_time = if_get_wait_for_sync_interval();
544 ictl.timer_running = iface->ldp_sync.wait_for_sync_timer ? true : false;
545
546 ictl.wait_time_remaining =
547 thread_timer_remain_second(iface->ldp_sync.wait_for_sync_timer);
548
549 memset(&ictl.peer_ldp_id, 0, sizeof(ictl.peer_ldp_id));
550
551 ldp_sync_get_peer_ldp_id(iface, &ictl.peer_ldp_id);
552
553 return (&ictl);
554 }
555
556 /* multicast membership sockopts */
557 in_addr_t
558 if_get_ipv4_addr(struct iface *iface)
559 {
560 struct if_addr *if_addr;
561
562 LIST_FOREACH(if_addr, &iface->addr_list, entry)
563 if (if_addr->af == AF_INET)
564 return (if_addr->addr.v4.s_addr);
565
566 return (INADDR_ANY);
567 }
568
569 static int
570 if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
571 {
572 struct in_addr if_addr;
573
574 log_debug("%s: interface %s addr %pI4", __func__, iface->name,
575 addr);
576
577 if_addr.s_addr = if_get_ipv4_addr(iface);
578
579 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
580 IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
581 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %pI4",
582 __func__, iface->name, addr);
583 return (-1);
584 }
585 return (0);
586 }
587
588 static int
589 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
590 {
591 struct in_addr if_addr;
592
593 log_debug("%s: interface %s addr %pI4", __func__, iface->name,
594 addr);
595
596 if_addr.s_addr = if_get_ipv4_addr(iface);
597
598 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
599 IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
600 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s address %pI4", __func__, iface->name, addr);
601 return (-1);
602 }
603
604 return (0);
605 }
606
607 static int
608 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
609 {
610 struct ipv6_mreq mreq;
611
612 log_debug("%s: interface %s addr %s", __func__, iface->name,
613 log_in6addr(addr));
614
615 mreq.ipv6mr_multiaddr = *addr;
616 mreq.ipv6mr_interface = iface->ifindex;
617
618 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
619 IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) {
620 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
621 __func__, iface->name, log_in6addr(addr));
622 return (-1);
623 }
624
625 return (0);
626 }
627
628 static int
629 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
630 {
631 struct ipv6_mreq mreq;
632
633 log_debug("%s: interface %s addr %s", __func__, iface->name,
634 log_in6addr(addr));
635
636 mreq.ipv6mr_multiaddr = *addr;
637 mreq.ipv6mr_interface = iface->ifindex;
638
639 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
640 IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) {
641 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
642 __func__, iface->name, log_in6addr(addr));
643 return (-1);
644 }
645
646 return (0);
647 }
648
649 const struct {
650 int state;
651 enum ldp_sync_event event;
652 enum ldp_sync_action action;
653 int new_state;
654 } ldp_sync_fsm_tbl[] = {
655 /* current state event that happened action to take resulting state */
656 /* LDP IGP Sync not achieved */
657 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_LDP_SYNC_START, LDP_SYNC_ACT_LDP_START_SYNC, 0},
658 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_LDP_SYNC_COMPLETE, LDP_SYNC_ACT_LDP_COMPLETE_SYNC, LDP_SYNC_STA_ACH},
659 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_CONFIG_LDP_OFF, LDP_SYNC_ACT_CONFIG_LDP_OFF, 0},
660 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_IFACE_SHUTDOWN, LDP_SYNC_ACT_IFACE_SHUTDOWN, 0},
661 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_SESSION_CLOSE, LDP_SYNC_ACT_NOTHING, 0},
662 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_ADJ_DEL, LDP_SYNC_ACT_NOTHING, 0},
663 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_ADJ_NEW, LDP_SYNC_ACT_NOTHING, 0},
664 /* LDP IGP Sync achieved */
665 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_CONFIG_LDP_OFF, LDP_SYNC_ACT_CONFIG_LDP_OFF, LDP_SYNC_STA_NOT_ACH},
666 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_LDP_SYNC_COMPLETE, LDP_SYNC_ACT_NOTHING, 0},
667 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_LDP_SYNC_START, LDP_SYNC_ACT_NOTHING, 0},
668 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_IFACE_SHUTDOWN, LDP_SYNC_ACT_IFACE_SHUTDOWN, LDP_SYNC_STA_NOT_ACH},
669 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_SESSION_CLOSE, LDP_SYNC_ACT_IFACE_START_SYNC, LDP_SYNC_STA_NOT_ACH},
670 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_ADJ_DEL, LDP_SYNC_ACT_IFACE_START_SYNC, LDP_SYNC_STA_NOT_ACH},
671 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_ADJ_NEW, LDP_SYNC_ACT_NOTHING, 0},
672 {-1, LDP_SYNC_EVT_NOTHING, LDP_SYNC_ACT_NOTHING, 0},
673 };
674
675 const char * const ldp_sync_event_names[] = {
676 "NOTHING",
677 "LDP SYNC START",
678 "LDP SYNC COMPLETE",
679 "CONFIG LDP OFF",
680 "IFACE SYNC START (ADJ DEL)",
681 "IFACE SYNC START (ADJ NEW)",
682 "IFACE SYNC START (SESSION CLOSE)",
683 "IFACE SYNC START (CONFIG LDP ON)",
684 "IFACE SHUTDOWN",
685 "N/A"
686 };
687
688 const char * const ldp_sync_action_names[] = {
689 "NOTHING",
690 "IFACE SYNC START",
691 "LDP START SYNC",
692 "LDP COMPLETE SYNC",
693 "CONFIG LDP OFF",
694 "IFACE SHUTDOWN",
695 "N/A"
696 };
697
698 const char *
699 ldp_sync_state_name(int state)
700 {
701 switch (state) {
702 case LDP_SYNC_STA_NOT_ACH:
703 return ("NOT ACHIEVED");
704 case LDP_SYNC_STA_ACH:
705 return ("ACHIEVED");
706 default:
707 return ("UNKNOWN");
708 }
709 }
710
711 static int
712 send_ldp_sync_state_update(char *name, int ifindex, int sync_start)
713 {
714 debug_evt_ldp_sync("%s: interface %s (%d), sync_start=%d",
715 __func__, name, ifindex, sync_start);
716
717 struct ldp_igp_sync_if_state state;
718
719 state.ifindex = ifindex;
720 state.sync_start = sync_start;
721
722 return ldpe_imsg_compose_parent(IMSG_LDP_SYNC_IF_STATE_UPDATE,
723 getpid(), &state, sizeof(state));
724 }
725
726 static int
727 ldp_sync_act_iface_start_sync(struct iface *iface)
728 {
729 send_ldp_sync_state_update(iface->name, iface->ifindex, true);
730
731 return (0);
732 }
733
734 static void iface_wait_for_ldp_sync_timer(struct thread *thread)
735 {
736 struct iface *iface = THREAD_ARG(thread);
737
738 ldp_sync_fsm(iface, LDP_SYNC_EVT_LDP_SYNC_COMPLETE);
739 }
740
741 static void start_wait_for_ldp_sync_timer(struct iface *iface)
742 {
743 if (iface->ldp_sync.wait_for_sync_timer)
744 return;
745
746 THREAD_OFF(iface->ldp_sync.wait_for_sync_timer);
747 thread_add_timer(master, iface_wait_for_ldp_sync_timer, iface,
748 if_get_wait_for_sync_interval(),
749 &iface->ldp_sync.wait_for_sync_timer);
750 }
751
752 static void stop_wait_for_ldp_sync_timer(struct iface *iface)
753 {
754 THREAD_OFF(iface->ldp_sync.wait_for_sync_timer);
755 }
756
757 static int
758 ldp_sync_act_ldp_start_sync(struct iface *iface)
759 {
760 start_wait_for_ldp_sync_timer(iface);
761
762 return 0;
763 }
764
765 static int
766 ldp_sync_act_ldp_complete_sync(struct iface *iface)
767 {
768 send_ldp_sync_state_update(iface->name, iface->ifindex, false);
769
770 return 0;
771 }
772
773 static int
774 iface_to_oper_nbr_count(struct iface *iface, unsigned int type)
775 {
776 int oper_nbr_count = 0;
777 struct adj *adj;
778
779 RB_FOREACH(adj, ia_adj_head, &iface->ipv4.adj_tree) {
780 if (type == adj->source.type && adj->nbr &&
781 adj->nbr->state == NBR_STA_OPER)
782 oper_nbr_count++;
783 }
784
785 RB_FOREACH(adj, ia_adj_head, &iface->ipv6.adj_tree) {
786 if (type == adj->source.type && adj->nbr &&
787 adj->nbr->state == NBR_STA_OPER)
788 oper_nbr_count++;
789 }
790
791 return oper_nbr_count;
792 }
793
794 int
795 ldp_sync_fsm_adj_event(struct adj *adj, enum ldp_sync_event event)
796 {
797 if (adj->source.type != HELLO_LINK)
798 return -1;
799
800 struct iface *iface = adj->source.link.ia->iface;
801
802 if (!iface->operative)
803 return 0;
804
805 if (event == LDP_SYNC_EVT_ADJ_NEW) {
806 struct nbr *nbr = adj->nbr;
807 if (nbr && nbr->state == NBR_STA_OPER) {
808 event = LDP_SYNC_EVT_LDP_SYNC_START;
809 }
810 } else if (event == LDP_SYNC_EVT_ADJ_DEL) {
811 /* Ignore if an operational neighbor exists.
812 */
813 int oper_nbr_count = iface_to_oper_nbr_count(iface, HELLO_LINK);
814 if (oper_nbr_count > 0)
815 return 0;
816 }
817
818 debug_evt_ldp_sync("%s: event %s, "
819 "adj iface %s (%d) lsr-id %pI4 "
820 "source address %s transport address %s",
821 __func__, ldp_sync_event_names[event],
822 adj->source.link.ia->iface->name,
823 adj->source.link.ia->iface->ifindex,
824 &adj->lsr_id,
825 log_addr(adj_get_af(adj), &adj->source.link.src_addr),
826 log_addr(adj_get_af(adj), &adj->trans_addr));
827
828 return ldp_sync_fsm(iface, event);
829 }
830
831 int
832 ldp_sync_fsm_nbr_event(struct nbr *nbr, enum ldp_sync_event event)
833 {
834 struct adj *adj;
835 struct iface *iface = NULL;
836 RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree) {
837 if (HELLO_LINK != adj->source.type)
838 continue;
839
840 iface = adj->source.link.ia->iface;
841
842 if (!iface || !iface->operative)
843 continue;
844
845 int oper_nbr_count = iface_to_oper_nbr_count(iface, HELLO_LINK);
846
847 if (event == LDP_SYNC_EVT_SESSION_CLOSE && oper_nbr_count > 0)
848 /* Ignore if an operational neighbor exists.
849 */
850 continue;
851
852 debug_evt_ldp_sync("%s: event %s, iface %s, lsr-id %pI4",
853 __func__, ldp_sync_event_names[event],
854 iface->name, &nbr->id);
855
856 ldp_sync_fsm(iface, event);
857 }
858
859 return 0;
860 }
861
862 int
863 ldp_sync_fsm_state_req(struct ldp_igp_sync_if_state_req *state_req)
864 {
865 debug_evt_ldp_sync("%s: interface %s (%d) proto %s",
866 __func__, state_req->name, state_req->ifindex,
867 zebra_route_string(state_req->proto));
868
869 struct iface *iface = if_lookup_name(leconf, state_req->name);
870
871 if (!iface) {
872 debug_evt_ldp_sync("%s: Warning: Ignoring LDP IGP SYNC "
873 "interface state request for interface %s (%d). "
874 "Interface does not exist in LDP.",
875 __func__, state_req->name, state_req->ifindex);
876
877 return 0;
878 }
879
880 return send_ldp_sync_state_update(state_req->name,
881 state_req->ifindex,
882 (iface->ldp_sync.state != LDP_SYNC_STA_ACH));
883 }
884
885 static int
886 ldp_sync_fsm_init(struct iface *iface, int state)
887 {
888 int old_state = iface->ldp_sync.state;
889
890 iface->ldp_sync.state = state;
891 stop_wait_for_ldp_sync_timer(iface);
892
893 send_ldp_sync_state_update(iface->name, iface->ifindex,
894 (iface->ldp_sync.state != LDP_SYNC_STA_ACH));
895
896 if (old_state != iface->ldp_sync.state) {
897 debug_evt_ldp_sync("%s: resulted in "
898 "changing state for interface %s (%d) from %s to %s",
899 __func__,
900 iface->name, iface->ifindex,
901 ldp_sync_state_name(old_state),
902 ldp_sync_state_name(iface->ldp_sync.state));
903 }
904
905 return 0;
906 }
907
908 int
909 ldp_sync_fsm(struct iface *iface, enum ldp_sync_event event)
910 {
911 int old_state = iface->ldp_sync.state;
912 int new_state = 0;
913 int i;
914
915 for (i = 0; ldp_sync_fsm_tbl[i].state != -1; i++)
916 if ((ldp_sync_fsm_tbl[i].state & old_state) &&
917 (ldp_sync_fsm_tbl[i].event == event)) {
918 new_state = ldp_sync_fsm_tbl[i].new_state;
919 break;
920 }
921
922 if (ldp_sync_fsm_tbl[i].state == -1) {
923 /* event outside of the defined fsm, ignore it. */
924 log_warnx("%s: interface %s, event %s not expected in "
925 "state %s ", __func__, iface->name,
926 ldp_sync_event_names[event],
927 ldp_sync_state_name(old_state));
928 return (0);
929 }
930
931 if (new_state != 0)
932 iface->ldp_sync.state = new_state;
933
934 switch (ldp_sync_fsm_tbl[i].action) {
935 case LDP_SYNC_ACT_IFACE_START_SYNC:
936 ldp_sync_act_iface_start_sync(iface);
937 break;
938 case LDP_SYNC_ACT_LDP_START_SYNC:
939 ldp_sync_act_ldp_start_sync(iface);
940 break;
941 case LDP_SYNC_ACT_LDP_COMPLETE_SYNC:
942 ldp_sync_act_ldp_complete_sync(iface);
943 break;
944 case LDP_SYNC_ACT_CONFIG_LDP_OFF:
945 ldp_sync_fsm_init(iface, LDP_SYNC_STA_NOT_ACH);
946 break;
947 case LDP_SYNC_ACT_IFACE_SHUTDOWN:
948 ldp_sync_fsm_init(iface, iface->ldp_sync.state);
949 break;
950 case LDP_SYNC_ACT_NOTHING:
951 /* do nothing */
952 break;
953 }
954
955 if (old_state != iface->ldp_sync.state) {
956
957 debug_evt_ldp_sync("%s: event %s resulted in action %s "
958 "for interface %s, changing state from %s to %s",
959 __func__, ldp_sync_event_names[event],
960 ldp_sync_action_names[ldp_sync_fsm_tbl[i].action],
961 iface->name, ldp_sync_state_name(old_state),
962 ldp_sync_state_name(iface->ldp_sync.state));
963
964 } else {
965 debug_evt_ldp_sync("%s: event %s resulted in action %s "
966 "for interface %s, remaining in state %s",
967 __func__, ldp_sync_event_names[event],
968 ldp_sync_action_names[ldp_sync_fsm_tbl[i].action],
969 iface->name,
970 ldp_sync_state_name(iface->ldp_sync.state));
971 }
972
973 return (0);
974 }
975
976 void
977 ldp_sync_fsm_reset_all(void)
978 {
979 struct iface *iface;
980
981 RB_FOREACH(iface, iface_head, &leconf->iface_tree)
982 ldp_sync_fsm(iface, LDP_SYNC_EVT_CONFIG_LDP_OFF);
983 }