]> git.proxmox.com Git - mirror_frr.git/blob - ldpd/interface.c
Merge pull request #7090 from dslicenc/comm-list-replace
[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 int if_hello_timer(struct 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 int 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 int
459 if_hello_timer(struct thread *thread)
460 {
461 struct iface_af *ia = THREAD_ARG(thread);
462
463 ia->hello_timer = NULL;
464 send_hello(HELLO_LINK, ia, NULL);
465 if_start_hello_timer(ia);
466
467 return (0);
468 }
469
470 static void
471 if_start_hello_timer(struct iface_af *ia)
472 {
473 THREAD_TIMER_OFF(ia->hello_timer);
474 ia->hello_timer = NULL;
475 thread_add_timer(master, if_hello_timer, ia, if_get_hello_interval(ia),
476 &ia->hello_timer);
477 }
478
479 static void
480 if_stop_hello_timer(struct iface_af *ia)
481 {
482 THREAD_TIMER_OFF(ia->hello_timer);
483 }
484
485 struct ctl_iface *
486 if_to_ctl(struct iface_af *ia)
487 {
488 static struct ctl_iface ictl;
489 struct timeval now;
490 struct adj *adj;
491
492 ictl.af = ia->af;
493 memcpy(ictl.name, ia->iface->name, sizeof(ictl.name));
494 ictl.ifindex = ia->iface->ifindex;
495 ictl.state = ia->state;
496 ictl.type = ia->iface->type;
497 ictl.hello_holdtime = if_get_hello_holdtime(ia);
498 ictl.hello_interval = if_get_hello_interval(ia);
499
500 gettimeofday(&now, NULL);
501 if (ia->state != IF_STA_DOWN &&
502 ia->uptime != 0) {
503 ictl.uptime = now.tv_sec - ia->uptime;
504 } else
505 ictl.uptime = 0;
506
507 ictl.adj_cnt = 0;
508 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
509 ictl.adj_cnt++;
510
511 return (&ictl);
512 }
513
514 static void
515 ldp_sync_get_peer_ldp_id(struct iface *iface, struct in_addr *peer_ldp_id)
516 {
517 struct iface_af *ia;
518 struct adj *adj;
519
520 if (iface->ipv4.state == IF_STA_ACTIVE) {
521 ia = iface_af_get(iface, AF_INET);
522 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
523 if (adj->nbr && adj->nbr->state == NBR_STA_OPER) {
524 *peer_ldp_id = adj->nbr->id;
525 return;
526 }
527 }
528
529 if (iface->ipv6.state == IF_STA_ACTIVE) {
530 ia = iface_af_get(iface, AF_INET6);
531 RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
532 if (adj->nbr && adj->nbr->state == NBR_STA_OPER) {
533 *peer_ldp_id = adj->nbr->id;
534 return;
535 }
536 }
537 }
538
539 struct ctl_ldp_sync *
540 ldp_sync_to_ctl(struct iface *iface)
541 {
542 static struct ctl_ldp_sync ictl;
543
544 memcpy(ictl.name, iface->name, sizeof(ictl.name));
545 ictl.ifindex = iface->ifindex;
546 ictl.in_sync = (iface->ldp_sync.state == LDP_SYNC_STA_ACH);
547 ictl.wait_time = if_get_wait_for_sync_interval();
548 ictl.timer_running = iface->ldp_sync.wait_for_sync_timer ? true : false;
549
550 if (iface->ldp_sync.wait_for_sync_timer)
551 ictl.wait_time_remaining =
552 thread_timer_remain_second(iface->ldp_sync.wait_for_sync_timer);
553 else
554 ictl.wait_time_remaining = 0;
555
556 memset(&ictl.peer_ldp_id, 0, sizeof(ictl.peer_ldp_id));
557
558 ldp_sync_get_peer_ldp_id(iface, &ictl.peer_ldp_id);
559
560 return (&ictl);
561 }
562
563 /* multicast membership sockopts */
564 in_addr_t
565 if_get_ipv4_addr(struct iface *iface)
566 {
567 struct if_addr *if_addr;
568
569 LIST_FOREACH(if_addr, &iface->addr_list, entry)
570 if (if_addr->af == AF_INET)
571 return (if_addr->addr.v4.s_addr);
572
573 return (INADDR_ANY);
574 }
575
576 static int
577 if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
578 {
579 struct in_addr if_addr;
580
581 log_debug("%s: interface %s addr %s", __func__, iface->name,
582 inet_ntoa(*addr));
583
584 if_addr.s_addr = if_get_ipv4_addr(iface);
585
586 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
587 IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
588 log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
589 __func__, iface->name, inet_ntoa(*addr));
590 return (-1);
591 }
592 return (0);
593 }
594
595 static int
596 if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
597 {
598 struct in_addr if_addr;
599
600 log_debug("%s: interface %s addr %s", __func__, iface->name,
601 inet_ntoa(*addr));
602
603 if_addr.s_addr = if_get_ipv4_addr(iface);
604
605 if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
606 IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
607 log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s address %s", __func__, iface->name, inet_ntoa(*addr));
608 return (-1);
609 }
610
611 return (0);
612 }
613
614 static int
615 if_join_ipv6_group(struct iface *iface, struct in6_addr *addr)
616 {
617 struct ipv6_mreq mreq;
618
619 log_debug("%s: interface %s addr %s", __func__, iface->name,
620 log_in6addr(addr));
621
622 mreq.ipv6mr_multiaddr = *addr;
623 mreq.ipv6mr_interface = iface->ifindex;
624
625 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
626 IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) {
627 log_warn("%s: error IPV6_JOIN_GROUP, interface %s address %s",
628 __func__, iface->name, log_in6addr(addr));
629 return (-1);
630 }
631
632 return (0);
633 }
634
635 static int
636 if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
637 {
638 struct ipv6_mreq mreq;
639
640 log_debug("%s: interface %s addr %s", __func__, iface->name,
641 log_in6addr(addr));
642
643 mreq.ipv6mr_multiaddr = *addr;
644 mreq.ipv6mr_interface = iface->ifindex;
645
646 if (setsockopt(global.ipv6.ldp_disc_socket, IPPROTO_IPV6,
647 IPV6_LEAVE_GROUP, (void *)&mreq, sizeof(mreq)) < 0) {
648 log_warn("%s: error IPV6_LEAVE_GROUP, interface %s address %s",
649 __func__, iface->name, log_in6addr(addr));
650 return (-1);
651 }
652
653 return (0);
654 }
655
656 const struct {
657 int state;
658 enum ldp_sync_event event;
659 enum ldp_sync_action action;
660 int new_state;
661 } ldp_sync_fsm_tbl[] = {
662 /* current state event that happened action to take resulting state */
663 /* LDP IGP Sync not achieved */
664 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_LDP_SYNC_START, LDP_SYNC_ACT_LDP_START_SYNC, 0},
665 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_LDP_SYNC_COMPLETE, LDP_SYNC_ACT_LDP_COMPLETE_SYNC, LDP_SYNC_STA_ACH},
666 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_CONFIG_LDP_OFF, LDP_SYNC_ACT_CONFIG_LDP_OFF, 0},
667 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_IFACE_SHUTDOWN, LDP_SYNC_ACT_IFACE_SHUTDOWN, 0},
668 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_SESSION_CLOSE, LDP_SYNC_ACT_NOTHING, 0},
669 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_ADJ_DEL, LDP_SYNC_ACT_NOTHING, 0},
670 {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_ADJ_NEW, LDP_SYNC_ACT_NOTHING, 0},
671 /* LDP IGP Sync achieved */
672 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_CONFIG_LDP_OFF, LDP_SYNC_ACT_CONFIG_LDP_OFF, LDP_SYNC_STA_NOT_ACH},
673 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_LDP_SYNC_COMPLETE, LDP_SYNC_ACT_NOTHING, 0},
674 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_LDP_SYNC_START, LDP_SYNC_ACT_NOTHING, 0},
675 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_IFACE_SHUTDOWN, LDP_SYNC_ACT_IFACE_SHUTDOWN, LDP_SYNC_STA_NOT_ACH},
676 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_SESSION_CLOSE, LDP_SYNC_ACT_IFACE_START_SYNC, LDP_SYNC_STA_NOT_ACH},
677 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_ADJ_DEL, LDP_SYNC_ACT_IFACE_START_SYNC, LDP_SYNC_STA_NOT_ACH},
678 {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_ADJ_NEW, LDP_SYNC_ACT_NOTHING, 0},
679 {-1, LDP_SYNC_EVT_NOTHING, LDP_SYNC_ACT_NOTHING, 0},
680 };
681
682 const char * const ldp_sync_event_names[] = {
683 "NOTHING",
684 "LDP SYNC START",
685 "LDP SYNC COMPLETE",
686 "CONFIG LDP OFF",
687 "IFACE SYNC START (ADJ DEL)",
688 "IFACE SYNC START (ADJ NEW)",
689 "IFACE SYNC START (SESSION CLOSE)",
690 "IFACE SYNC START (CONFIG LDP ON)",
691 "IFACE SHUTDOWN",
692 "N/A"
693 };
694
695 const char * const ldp_sync_action_names[] = {
696 "NOTHING",
697 "IFACE SYNC START",
698 "LDP START SYNC",
699 "LDP COMPLETE SYNC",
700 "CONFIG LDP OFF",
701 "IFACE SHUTDOWN",
702 "N/A"
703 };
704
705 const char *
706 ldp_sync_state_name(int state)
707 {
708 switch (state) {
709 case LDP_SYNC_STA_NOT_ACH:
710 return ("NOT ACHIEVED");
711 case LDP_SYNC_STA_ACH:
712 return ("ACHIEVED");
713 default:
714 return ("UNKNOWN");
715 }
716 }
717
718 static int
719 send_ldp_sync_state_update(char *name, int ifindex, int sync_start)
720 {
721 debug_evt_ldp_sync("%s: interface %s (%d), sync_start=%d",
722 __func__, name, ifindex, sync_start);
723
724 struct ldp_igp_sync_if_state state;
725
726 state.ifindex = ifindex;
727 state.sync_start = sync_start;
728
729 return ldpe_imsg_compose_parent(IMSG_LDP_SYNC_IF_STATE_UPDATE,
730 getpid(), &state, sizeof(state));
731 }
732
733 static int
734 ldp_sync_act_iface_start_sync(struct iface *iface)
735 {
736 send_ldp_sync_state_update(iface->name, iface->ifindex, true);
737
738 return (0);
739 }
740
741 static int
742 iface_wait_for_ldp_sync_timer(struct thread *thread)
743 {
744 struct iface *iface = THREAD_ARG(thread);
745
746 ldp_sync_fsm(iface, LDP_SYNC_EVT_LDP_SYNC_COMPLETE);
747
748 return (0);
749 }
750
751 static void start_wait_for_ldp_sync_timer(struct iface *iface)
752 {
753 if (iface->ldp_sync.wait_for_sync_timer)
754 return;
755
756 THREAD_TIMER_OFF(iface->ldp_sync.wait_for_sync_timer);
757 iface->ldp_sync.wait_for_sync_timer = NULL;
758 thread_add_timer(master, iface_wait_for_ldp_sync_timer, iface,
759 if_get_wait_for_sync_interval(),
760 &iface->ldp_sync.wait_for_sync_timer);
761 }
762
763 static void stop_wait_for_ldp_sync_timer(struct iface *iface)
764 {
765 THREAD_TIMER_OFF(iface->ldp_sync.wait_for_sync_timer);
766 iface->ldp_sync.wait_for_sync_timer = NULL;
767 }
768
769 static int
770 ldp_sync_act_ldp_start_sync(struct iface *iface)
771 {
772 start_wait_for_ldp_sync_timer(iface);
773
774 return 0;
775 }
776
777 static int
778 ldp_sync_act_ldp_complete_sync(struct iface *iface)
779 {
780 send_ldp_sync_state_update(iface->name, iface->ifindex, false);
781
782 return 0;
783 }
784
785 static int
786 iface_to_oper_nbr_count(struct iface *iface, unsigned int type)
787 {
788 int oper_nbr_count = 0;
789 struct adj *adj;
790
791 RB_FOREACH(adj, ia_adj_head, &iface->ipv4.adj_tree) {
792 if (type == adj->source.type && adj->nbr &&
793 adj->nbr->state == NBR_STA_OPER)
794 oper_nbr_count++;
795 }
796
797 RB_FOREACH(adj, ia_adj_head, &iface->ipv6.adj_tree) {
798 if (type == adj->source.type && adj->nbr &&
799 adj->nbr->state == NBR_STA_OPER)
800 oper_nbr_count++;
801 }
802
803 return oper_nbr_count;
804 }
805
806 int
807 ldp_sync_fsm_adj_event(struct adj *adj, enum ldp_sync_event event)
808 {
809 if (adj->source.type != HELLO_LINK)
810 return -1;
811
812 struct iface *iface = adj->source.link.ia->iface;
813
814 if (!iface->operative)
815 return 0;
816
817 if (event == LDP_SYNC_EVT_ADJ_NEW) {
818 struct nbr *nbr = adj->nbr;
819 if (nbr && nbr->state == NBR_STA_OPER) {
820 event = LDP_SYNC_EVT_LDP_SYNC_START;
821 }
822 } else if (event == LDP_SYNC_EVT_ADJ_DEL) {
823 /* Ignore if an operational neighbor exists.
824 */
825 int oper_nbr_count = iface_to_oper_nbr_count(iface, HELLO_LINK);
826 if (oper_nbr_count > 0)
827 return 0;
828 }
829
830 debug_evt_ldp_sync("%s: event %s, "
831 "adj iface %s (%d) lsr-id %s "
832 "source address %s transport address %s",
833 __func__, ldp_sync_event_names[event],
834 adj->source.link.ia->iface->name,
835 adj->source.link.ia->iface->ifindex,
836 inet_ntoa(adj->lsr_id),
837 log_addr(adj_get_af(adj), &adj->source.link.src_addr),
838 log_addr(adj_get_af(adj), &adj->trans_addr));
839
840 return ldp_sync_fsm(iface, event);
841 }
842
843 int
844 ldp_sync_fsm_nbr_event(struct nbr *nbr, enum ldp_sync_event event)
845 {
846 struct adj *adj;
847 struct iface *iface = NULL;
848 RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree) {
849 if (HELLO_LINK != adj->source.type)
850 continue;
851
852 iface = adj->source.link.ia->iface;
853
854 if (!iface || !iface->operative)
855 continue;
856
857 int oper_nbr_count = iface_to_oper_nbr_count(iface, HELLO_LINK);
858
859 if (event == LDP_SYNC_EVT_SESSION_CLOSE && oper_nbr_count > 0)
860 /* Ignore if an operational neighbor exists.
861 */
862 continue;
863
864 debug_evt_ldp_sync("%s: event %s, iface %s, lsr-id %s",
865 __func__, ldp_sync_event_names[event],
866 iface->name, inet_ntoa(nbr->id));
867
868 ldp_sync_fsm(iface, event);
869 }
870
871 return 0;
872 }
873
874 int
875 ldp_sync_fsm_state_req(struct ldp_igp_sync_if_state_req *state_req)
876 {
877 debug_evt_ldp_sync("%s: interface %s (%d) proto %s",
878 __func__, state_req->name, state_req->ifindex,
879 zebra_route_string(state_req->proto));
880
881 struct iface *iface = if_lookup_name(leconf, state_req->name);
882
883 if (!iface) {
884 debug_evt_ldp_sync("%s: Warning: Ignoring LDP IGP SYNC "
885 "interface state request for interface %s (%d). "
886 "Interface does not exist in LDP.",
887 __func__, state_req->name, state_req->ifindex);
888
889 return 0;
890 }
891
892 return send_ldp_sync_state_update(state_req->name,
893 state_req->ifindex,
894 (iface->ldp_sync.state != LDP_SYNC_STA_ACH));
895 }
896
897 static int
898 ldp_sync_fsm_init(struct iface *iface, int state)
899 {
900 int old_state = iface->ldp_sync.state;
901
902 iface->ldp_sync.state = state;
903 stop_wait_for_ldp_sync_timer(iface);
904
905 send_ldp_sync_state_update(iface->name, iface->ifindex,
906 (iface->ldp_sync.state != LDP_SYNC_STA_ACH));
907
908 if (old_state != iface->ldp_sync.state) {
909 debug_evt_ldp_sync("%s: resulted in "
910 "changing state for interface %s (%d) from %s to %s",
911 __func__,
912 iface->name, iface->ifindex,
913 ldp_sync_state_name(old_state),
914 ldp_sync_state_name(iface->ldp_sync.state));
915 }
916
917 return 0;
918 }
919
920 int
921 ldp_sync_fsm(struct iface *iface, enum ldp_sync_event event)
922 {
923 int old_state = iface->ldp_sync.state;
924 int new_state = 0;
925 int i;
926
927 for (i = 0; ldp_sync_fsm_tbl[i].state != -1; i++)
928 if ((ldp_sync_fsm_tbl[i].state & old_state) &&
929 (ldp_sync_fsm_tbl[i].event == event)) {
930 new_state = ldp_sync_fsm_tbl[i].new_state;
931 break;
932 }
933
934 if (ldp_sync_fsm_tbl[i].state == -1) {
935 /* event outside of the defined fsm, ignore it. */
936 log_warnx("%s: interface %s, event %s not expected in "
937 "state %s ", __func__, iface->name,
938 ldp_sync_event_names[event],
939 ldp_sync_state_name(old_state));
940 return (0);
941 }
942
943 if (new_state != 0)
944 iface->ldp_sync.state = new_state;
945
946 switch (ldp_sync_fsm_tbl[i].action) {
947 case LDP_SYNC_ACT_IFACE_START_SYNC:
948 ldp_sync_act_iface_start_sync(iface);
949 break;
950 case LDP_SYNC_ACT_LDP_START_SYNC:
951 ldp_sync_act_ldp_start_sync(iface);
952 break;
953 case LDP_SYNC_ACT_LDP_COMPLETE_SYNC:
954 ldp_sync_act_ldp_complete_sync(iface);
955 break;
956 case LDP_SYNC_ACT_CONFIG_LDP_OFF:
957 ldp_sync_fsm_init(iface, LDP_SYNC_STA_NOT_ACH);
958 break;
959 case LDP_SYNC_ACT_IFACE_SHUTDOWN:
960 ldp_sync_fsm_init(iface, iface->ldp_sync.state);
961 break;
962 case LDP_SYNC_ACT_NOTHING:
963 /* do nothing */
964 break;
965 }
966
967 if (old_state != iface->ldp_sync.state) {
968
969 debug_evt_ldp_sync("%s: event %s resulted in action %s "
970 "for interface %s, changing state from %s to %s",
971 __func__, ldp_sync_event_names[event],
972 ldp_sync_action_names[ldp_sync_fsm_tbl[i].action],
973 iface->name, ldp_sync_state_name(old_state),
974 ldp_sync_state_name(iface->ldp_sync.state));
975
976 } else {
977 debug_evt_ldp_sync("%s: event %s resulted in action %s "
978 "for interface %s, remaining in state %s",
979 __func__, ldp_sync_event_names[event],
980 ldp_sync_action_names[ldp_sync_fsm_tbl[i].action],
981 iface->name,
982 ldp_sync_state_name(iface->ldp_sync.state));
983 }
984
985 return (0);
986 }
987
988 void
989 ldp_sync_fsm_reset_all(void)
990 {
991 struct iface *iface;
992
993 RB_FOREACH(iface, iface_head, &leconf->iface_tree)
994 ldp_sync_fsm(iface, LDP_SYNC_EVT_CONFIG_LDP_OFF);
995 }