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>
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.
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.
26 #include "ldp_debug.h"
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
*);
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
);
55 RB_GENERATE(iface_head
, iface
, entry
, iface_compare
)
58 iface_compare(const struct iface
*a
, const struct iface
*b
)
60 return if_cmp_name_func(a
->name
, b
->name
);
64 if_new(const char *name
)
68 if ((iface
= calloc(1, sizeof(*iface
))) == NULL
)
69 fatal("if_new: calloc");
71 strlcpy(iface
->name
, name
, sizeof(iface
->name
));
74 iface
->ipv4
.af
= AF_INET
;
75 iface
->ipv4
.iface
= iface
;
76 iface
->ipv4
.enabled
= 0;
79 iface
->ipv6
.af
= AF_INET6
;
80 iface
->ipv6
.iface
= iface
;
81 iface
->ipv6
.enabled
= 0;
87 ldpe_if_init(struct iface
*iface
)
89 log_debug("%s: interface %s", __func__
, iface
->name
);
91 LIST_INIT(&iface
->addr_list
);
94 iface
->ipv4
.iface
= iface
;
95 iface
->ipv4
.state
= IF_STA_DOWN
;
96 RB_INIT(ia_adj_head
, &iface
->ipv4
.adj_tree
);
99 iface
->ipv6
.iface
= iface
;
100 iface
->ipv6
.state
= IF_STA_DOWN
;
101 RB_INIT(ia_adj_head
, &iface
->ipv6
.adj_tree
);
104 ldp_sync_fsm_init(iface
, LDP_SYNC_STA_NOT_ACH
);
108 ldpe_if_exit(struct iface
*iface
)
110 struct if_addr
*if_addr
;
112 log_debug("%s: interface %s", __func__
, iface
->name
);
114 ldp_sync_fsm(iface
, LDP_SYNC_EVT_CONFIG_LDP_OFF
);
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
);
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
));
129 if_lookup(struct ldpd_conf
*xconf
, ifindex_t ifindex
)
133 RB_FOREACH(iface
, iface_head
, &xconf
->iface_tree
)
134 if (iface
->ifindex
== ifindex
)
141 if_lookup_name(struct ldpd_conf
*xconf
, const char *ifname
)
144 strlcpy(iface
.name
, ifname
, sizeof(iface
.name
));
145 return (RB_FIND(iface_head
, &xconf
->iface_tree
, &iface
));
149 if_update_info(struct iface
*iface
, struct kif
*kif
)
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
;
158 if (ldpd_process
== PROC_LDP_ENGINE
&& iface
->operative
&&
160 ldp_sync_fsm(iface
, LDP_SYNC_EVT_IFACE_SHUTDOWN
);
162 /* get index and flags */
163 iface
->ifindex
= kif
->ifindex
;
164 iface
->operative
= kif
->operative
;
168 iface_af_get(struct iface
*iface
, int af
)
172 return (&iface
->ipv4
);
174 return (&iface
->ipv6
);
176 fatalx("iface_af_get: unknown af");
180 static struct if_addr
*
181 if_addr_new(struct kaddr
*ka
)
183 struct if_addr
*if_addr
;
185 if ((if_addr
= calloc(1, sizeof(*if_addr
))) == NULL
)
188 if_addr
->af
= ka
->af
;
189 if_addr
->addr
= ka
->addr
;
190 if_addr
->prefixlen
= ka
->prefixlen
;
191 if_addr
->dstbrd
= ka
->dstbrd
;
196 static struct if_addr
*
197 if_addr_lookup(struct if_addr_head
*addr_list
, struct kaddr
*ka
)
199 struct if_addr
*if_addr
;
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
))
212 if_addr_add(struct kaddr
*ka
)
215 struct if_addr
*if_addr
;
218 if (if_addr_lookup(&global
.addr_list
, ka
) == NULL
) {
219 if_addr
= if_addr_new(ka
);
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
)
225 if (if_addr
->af
== AF_INET
&& !nbr
->v4_enabled
)
227 if (if_addr
->af
== AF_INET6
&& !nbr
->v6_enabled
)
230 send_address_single(nbr
, if_addr
, 0);
234 iface
= if_lookup_name(leconf
, ka
->ifname
);
236 if (ka
->af
== AF_INET6
&& IN6_IS_ADDR_LINKLOCAL(&ka
->addr
.v6
))
237 iface
->linklocal
= ka
->addr
.v6
;
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
);
248 if_addr_del(struct kaddr
*ka
)
251 struct if_addr
*if_addr
;
254 iface
= if_lookup_name(leconf
, ka
->ifname
);
256 if (ka
->af
== AF_INET6
&&
257 IN6_ARE_ADDR_EQUAL(&iface
->linklocal
, &ka
->addr
.v6
))
258 memset(&iface
->linklocal
, 0, sizeof(iface
->linklocal
));
260 if_addr
= if_addr_lookup(&iface
->addr_list
, ka
);
262 LIST_REMOVE(if_addr
, entry
);
263 ldp_if_update(iface
, if_addr
->af
);
268 if_addr
= if_addr_lookup(&global
.addr_list
, ka
);
270 RB_FOREACH(nbr
, nbr_id_head
, &nbrs_by_id
) {
271 if (nbr
->state
!= NBR_STA_OPER
)
273 if (if_addr
->af
== AF_INET
&& !nbr
->v4_enabled
)
275 if (if_addr
->af
== AF_INET6
&& !nbr
->v6_enabled
)
277 send_address_single(nbr
, if_addr
, 1);
279 LIST_REMOVE(if_addr
, entry
);
285 if_start(struct iface
*iface
, int af
)
290 log_debug("%s: %s address-family %s", __func__
, iface
->name
,
293 ia
= iface_af_get(iface
, af
);
295 gettimeofday(&now
, NULL
);
296 ia
->uptime
= now
.tv_sec
;
300 if (if_join_ipv4_group(iface
, &global
.mcast_addr_v4
))
304 if (if_join_ipv6_group(iface
, &global
.mcast_addr_v6
))
308 fatalx("if_start: unknown af");
311 send_hello(HELLO_LINK
, ia
, NULL
);
312 if_start_hello_timer(ia
);
313 ia
->state
= IF_STA_ACTIVE
;
319 if_reset(struct iface
*iface
, int af
)
324 log_debug("%s: %s address-family %s", __func__
, iface
->name
,
327 ia
= iface_af_get(iface
, af
);
328 if_stop_hello_timer(ia
);
330 while (!RB_EMPTY(ia_adj_head
, &ia
->adj_tree
)) {
331 adj
= RB_ROOT(ia_adj_head
, &ia
->adj_tree
);
333 adj_del(adj
, S_SHUTDOWN
);
339 if (global
.ipv4
.ldp_disc_socket
!= -1)
340 if_leave_ipv4_group(iface
, &global
.mcast_addr_v4
);
343 if (global
.ipv6
.ldp_disc_socket
!= -1)
344 if_leave_ipv6_group(iface
, &global
.mcast_addr_v6
);
347 fatalx("if_reset: unknown af");
350 ia
->state
= IF_STA_DOWN
;
356 if_update_af(struct iface_af
*ia
)
358 int addr_ok
= 0, socket_ok
, rtr_id_ok
;
359 struct if_addr
*if_addr
;
364 * NOTE: for LDPv4, each interface should have at least one
365 * valid IP address otherwise they can not be enabled.
367 LIST_FOREACH(if_addr
, &ia
->iface
->addr_list
, entry
) {
368 if (if_addr
->af
== AF_INET
) {
375 /* for IPv6 the link-local address is enough. */
376 if (IN6_IS_ADDR_LINKLOCAL(&ia
->iface
->linklocal
))
380 fatalx("if_update_af: unknown af");
383 if ((ldp_af_global_get(&global
, ia
->af
))->ldp_disc_socket
!= -1)
388 if (ldp_rtr_id_get(leconf
) != INADDR_ANY
)
393 if (ia
->state
== IF_STA_DOWN
) {
394 if (!ia
->enabled
|| !ia
->iface
->operative
|| !addr_ok
||
395 !socket_ok
|| !rtr_id_ok
)
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
)
404 if_reset(ia
->iface
, ia
->af
);
409 ldp_if_update(struct iface
*iface
, int af
)
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
);
418 if_update_all(int af
)
422 RB_FOREACH(iface
, iface_head
, &leconf
->iface_tree
)
423 ldp_if_update(iface
, af
);
427 if_get_hello_holdtime(struct iface_af
*ia
)
429 if (ia
->hello_holdtime
!= 0)
430 return (ia
->hello_holdtime
);
432 if ((ldp_af_conf_get(leconf
, ia
->af
))->lhello_holdtime
!= 0)
433 return ((ldp_af_conf_get(leconf
, ia
->af
))->lhello_holdtime
);
435 return (leconf
->lhello_holdtime
);
439 if_get_hello_interval(struct iface_af
*ia
)
441 if (ia
->hello_interval
!= 0)
442 return (ia
->hello_interval
);
444 if ((ldp_af_conf_get(leconf
, ia
->af
))->lhello_interval
!= 0)
445 return ((ldp_af_conf_get(leconf
, ia
->af
))->lhello_interval
);
447 return (leconf
->lhello_interval
);
451 if_get_wait_for_sync_interval(void)
453 return (leconf
->wait_for_sync_interval
);
459 if_hello_timer(struct thread
*thread
)
461 struct iface_af
*ia
= THREAD_ARG(thread
);
463 ia
->hello_timer
= NULL
;
464 send_hello(HELLO_LINK
, ia
, NULL
);
465 if_start_hello_timer(ia
);
471 if_start_hello_timer(struct iface_af
*ia
)
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
),
480 if_stop_hello_timer(struct iface_af
*ia
)
482 THREAD_TIMER_OFF(ia
->hello_timer
);
486 if_to_ctl(struct iface_af
*ia
)
488 static struct ctl_iface ictl
;
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
);
500 gettimeofday(&now
, NULL
);
501 if (ia
->state
!= IF_STA_DOWN
&&
503 ictl
.uptime
= now
.tv_sec
- ia
->uptime
;
508 RB_FOREACH(adj
, ia_adj_head
, &ia
->adj_tree
)
515 ldp_sync_get_peer_ldp_id(struct iface
*iface
, struct in_addr
*peer_ldp_id
)
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
;
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
;
539 struct ctl_ldp_sync
*
540 ldp_sync_to_ctl(struct iface
*iface
)
542 static struct ctl_ldp_sync ictl
;
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;
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
);
554 ictl
.wait_time_remaining
= 0;
556 memset(&ictl
.peer_ldp_id
, 0, sizeof(ictl
.peer_ldp_id
));
558 ldp_sync_get_peer_ldp_id(iface
, &ictl
.peer_ldp_id
);
563 /* multicast membership sockopts */
565 if_get_ipv4_addr(struct iface
*iface
)
567 struct if_addr
*if_addr
;
569 LIST_FOREACH(if_addr
, &iface
->addr_list
, entry
)
570 if (if_addr
->af
== AF_INET
)
571 return (if_addr
->addr
.v4
.s_addr
);
577 if_join_ipv4_group(struct iface
*iface
, struct in_addr
*addr
)
579 struct in_addr if_addr
;
581 log_debug("%s: interface %s addr %s", __func__
, iface
->name
,
584 if_addr
.s_addr
= if_get_ipv4_addr(iface
);
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
));
596 if_leave_ipv4_group(struct iface
*iface
, struct in_addr
*addr
)
598 struct in_addr if_addr
;
600 log_debug("%s: interface %s addr %s", __func__
, iface
->name
,
603 if_addr
.s_addr
= if_get_ipv4_addr(iface
);
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
));
615 if_join_ipv6_group(struct iface
*iface
, struct in6_addr
*addr
)
617 struct ipv6_mreq mreq
;
619 log_debug("%s: interface %s addr %s", __func__
, iface
->name
,
622 mreq
.ipv6mr_multiaddr
= *addr
;
623 mreq
.ipv6mr_interface
= iface
->ifindex
;
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
));
636 if_leave_ipv6_group(struct iface
*iface
, struct in6_addr
*addr
)
638 struct ipv6_mreq mreq
;
640 log_debug("%s: interface %s addr %s", __func__
, iface
->name
,
643 mreq
.ipv6mr_multiaddr
= *addr
;
644 mreq
.ipv6mr_interface
= iface
->ifindex
;
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
));
658 enum ldp_sync_event event
;
659 enum ldp_sync_action action
;
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},
682 const char * const ldp_sync_event_names
[] = {
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)",
695 const char * const ldp_sync_action_names
[] = {
706 ldp_sync_state_name(int state
)
709 case LDP_SYNC_STA_NOT_ACH
:
710 return ("NOT ACHIEVED");
711 case LDP_SYNC_STA_ACH
:
719 send_ldp_sync_state_update(char *name
, int ifindex
, int sync_start
)
721 debug_evt_ldp_sync("%s: interface %s (%d), sync_start=%d",
722 __func__
, name
, ifindex
, sync_start
);
724 struct ldp_igp_sync_if_state state
;
726 state
.ifindex
= ifindex
;
727 state
.sync_start
= sync_start
;
729 return ldpe_imsg_compose_parent(IMSG_LDP_SYNC_IF_STATE_UPDATE
,
730 getpid(), &state
, sizeof(state
));
734 ldp_sync_act_iface_start_sync(struct iface
*iface
)
736 send_ldp_sync_state_update(iface
->name
, iface
->ifindex
, true);
742 iface_wait_for_ldp_sync_timer(struct thread
*thread
)
744 struct iface
*iface
= THREAD_ARG(thread
);
746 ldp_sync_fsm(iface
, LDP_SYNC_EVT_LDP_SYNC_COMPLETE
);
751 static void start_wait_for_ldp_sync_timer(struct iface
*iface
)
753 if (iface
->ldp_sync
.wait_for_sync_timer
)
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
);
763 static void stop_wait_for_ldp_sync_timer(struct iface
*iface
)
765 THREAD_TIMER_OFF(iface
->ldp_sync
.wait_for_sync_timer
);
766 iface
->ldp_sync
.wait_for_sync_timer
= NULL
;
770 ldp_sync_act_ldp_start_sync(struct iface
*iface
)
772 start_wait_for_ldp_sync_timer(iface
);
778 ldp_sync_act_ldp_complete_sync(struct iface
*iface
)
780 send_ldp_sync_state_update(iface
->name
, iface
->ifindex
, false);
786 iface_to_oper_nbr_count(struct iface
*iface
, unsigned int type
)
788 int oper_nbr_count
= 0;
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
)
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
)
803 return oper_nbr_count
;
807 ldp_sync_fsm_adj_event(struct adj
*adj
, enum ldp_sync_event event
)
809 if (adj
->source
.type
!= HELLO_LINK
)
812 struct iface
*iface
= adj
->source
.link
.ia
->iface
;
814 if (!iface
->operative
)
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
;
822 } else if (event
== LDP_SYNC_EVT_ADJ_DEL
) {
823 /* Ignore if an operational neighbor exists.
825 int oper_nbr_count
= iface_to_oper_nbr_count(iface
, HELLO_LINK
);
826 if (oper_nbr_count
> 0)
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
));
840 return ldp_sync_fsm(iface
, event
);
844 ldp_sync_fsm_nbr_event(struct nbr
*nbr
, enum ldp_sync_event event
)
847 struct iface
*iface
= NULL
;
848 RB_FOREACH(adj
, nbr_adj_head
, &nbr
->adj_tree
) {
849 if (HELLO_LINK
!= adj
->source
.type
)
852 iface
= adj
->source
.link
.ia
->iface
;
854 if (!iface
|| !iface
->operative
)
857 int oper_nbr_count
= iface_to_oper_nbr_count(iface
, HELLO_LINK
);
859 if (event
== LDP_SYNC_EVT_SESSION_CLOSE
&& oper_nbr_count
> 0)
860 /* Ignore if an operational neighbor exists.
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
));
868 ldp_sync_fsm(iface
, event
);
875 ldp_sync_fsm_state_req(struct ldp_igp_sync_if_state_req
*state_req
)
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
));
881 struct iface
*iface
= if_lookup_name(leconf
, state_req
->name
);
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
);
892 return send_ldp_sync_state_update(state_req
->name
,
894 (iface
->ldp_sync
.state
!= LDP_SYNC_STA_ACH
));
898 ldp_sync_fsm_init(struct iface
*iface
, int state
)
900 int old_state
= iface
->ldp_sync
.state
;
902 iface
->ldp_sync
.state
= state
;
903 stop_wait_for_ldp_sync_timer(iface
);
905 send_ldp_sync_state_update(iface
->name
, iface
->ifindex
,
906 (iface
->ldp_sync
.state
!= LDP_SYNC_STA_ACH
));
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",
912 iface
->name
, iface
->ifindex
,
913 ldp_sync_state_name(old_state
),
914 ldp_sync_state_name(iface
->ldp_sync
.state
));
921 ldp_sync_fsm(struct iface
*iface
, enum ldp_sync_event event
)
923 int old_state
= iface
->ldp_sync
.state
;
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
;
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
));
944 iface
->ldp_sync
.state
= new_state
;
946 switch (ldp_sync_fsm_tbl
[i
].action
) {
947 case LDP_SYNC_ACT_IFACE_START_SYNC
:
948 ldp_sync_act_iface_start_sync(iface
);
950 case LDP_SYNC_ACT_LDP_START_SYNC
:
951 ldp_sync_act_ldp_start_sync(iface
);
953 case LDP_SYNC_ACT_LDP_COMPLETE_SYNC
:
954 ldp_sync_act_ldp_complete_sync(iface
);
956 case LDP_SYNC_ACT_CONFIG_LDP_OFF
:
957 ldp_sync_fsm_init(iface
, LDP_SYNC_STA_NOT_ACH
);
959 case LDP_SYNC_ACT_IFACE_SHUTDOWN
:
960 ldp_sync_fsm_init(iface
, iface
->ldp_sync
.state
);
962 case LDP_SYNC_ACT_NOTHING
:
967 if (old_state
!= iface
->ldp_sync
.state
) {
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
));
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
],
982 ldp_sync_state_name(iface
->ldp_sync
.state
));
989 ldp_sync_fsm_reset_all(void)
993 RB_FOREACH(iface
, iface_head
, &leconf
->iface_tree
)
994 ldp_sync_fsm(iface
, LDP_SYNC_EVT_CONFIG_LDP_OFF
);