]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_bfd.c
pimd: When doing json output do not output non-json strings
[mirror_frr.git] / isisd / isis_bfd.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * IS-IS Rout(e)ing protocol - BFD support
4 * Copyright (C) 2018 Christian Franke
5 */
6 #include <zebra.h>
7
8 #include "zclient.h"
9 #include "nexthop.h"
10 #include "bfd.h"
11 #include "lib_errors.h"
12
13 #include "isisd/isis_bfd.h"
14 #include "isisd/isis_zebra.h"
15 #include "isisd/isis_common.h"
16 #include "isisd/isis_constants.h"
17 #include "isisd/isis_adjacency.h"
18 #include "isisd/isis_circuit.h"
19 #include "isisd/isisd.h"
20 #include "isisd/fabricd.h"
21
22 DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session");
23
24 static void adj_bfd_cb(struct bfd_session_params *bsp,
25 const struct bfd_session_status *bss, void *arg)
26 {
27 struct isis_adjacency *adj = arg;
28
29 if (IS_DEBUG_BFD)
30 zlog_debug(
31 "ISIS-BFD: BFD changed status for adjacency %s old %s new %s",
32 isis_adj_name(adj),
33 bfd_get_status_str(bss->previous_state),
34 bfd_get_status_str(bss->state));
35
36 if (bss->state == BFD_STATUS_DOWN
37 && bss->previous_state == BFD_STATUS_UP) {
38 adj->circuit->area->bfd_signalled_down = true;
39 isis_adj_state_change(&adj, ISIS_ADJ_DOWN,
40 "bfd session went down");
41 }
42 }
43
44 static void bfd_handle_adj_down(struct isis_adjacency *adj)
45 {
46 bfd_sess_free(&adj->bfd_session);
47 }
48
49 static void bfd_handle_adj_up(struct isis_adjacency *adj)
50 {
51 struct isis_circuit *circuit = adj->circuit;
52 int family;
53 union g_addr dst_ip;
54 union g_addr src_ip;
55 struct list *local_ips;
56 struct prefix *local_ip;
57
58 if (!circuit->bfd_config.enabled) {
59 if (IS_DEBUG_BFD)
60 zlog_debug(
61 "ISIS-BFD: skipping BFD initialization on adjacency with %s because BFD is not enabled for the circuit",
62 isis_adj_name(adj));
63 goto out;
64 }
65
66 /* If IS-IS IPv6 is configured wait for IPv6 address to be programmed
67 * before starting up BFD
68 */
69 if (circuit->ipv6_router
70 && (listcount(circuit->ipv6_link) == 0
71 || adj->ll_ipv6_count == 0)) {
72 if (IS_DEBUG_BFD)
73 zlog_debug(
74 "ISIS-BFD: skipping BFD initialization on adjacency with %s because IPv6 is enabled but not ready",
75 isis_adj_name(adj));
76 return;
77 }
78
79 /*
80 * If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer
81 * creating a BFD session over IPv6.
82 */
83 if (circuit->ipv6_router && adj->ll_ipv6_count) {
84 family = AF_INET6;
85 dst_ip.ipv6 = adj->ll_ipv6_addrs[0];
86 local_ips = circuit->ipv6_link;
87 if (list_isempty(local_ips)) {
88 if (IS_DEBUG_BFD)
89 zlog_debug(
90 "ISIS-BFD: skipping BFD initialization: IPv6 enabled and no local IPv6 addresses");
91 goto out;
92 }
93 local_ip = listgetdata(listhead(local_ips));
94 src_ip.ipv6 = local_ip->u.prefix6;
95 } else if (circuit->ip_router && adj->ipv4_address_count) {
96 family = AF_INET;
97 dst_ip.ipv4 = adj->ipv4_addresses[0];
98 local_ips = fabricd_ip_addrs(adj->circuit);
99 if (!local_ips || list_isempty(local_ips)) {
100 if (IS_DEBUG_BFD)
101 zlog_debug(
102 "ISIS-BFD: skipping BFD initialization: IPv4 enabled and no local IPv4 addresses");
103 goto out;
104 }
105 local_ip = listgetdata(listhead(local_ips));
106 src_ip.ipv4 = local_ip->u.prefix4;
107 } else
108 goto out;
109
110 if (adj->bfd_session == NULL)
111 adj->bfd_session = bfd_sess_new(adj_bfd_cb, adj);
112
113 bfd_sess_set_timers(adj->bfd_session, BFD_DEF_DETECT_MULT,
114 BFD_DEF_MIN_RX, BFD_DEF_MIN_TX);
115 if (family == AF_INET)
116 bfd_sess_set_ipv4_addrs(adj->bfd_session, &src_ip.ipv4,
117 &dst_ip.ipv4);
118 else
119 bfd_sess_set_ipv6_addrs(adj->bfd_session, &src_ip.ipv6,
120 &dst_ip.ipv6);
121 bfd_sess_set_interface(adj->bfd_session, adj->circuit->interface->name);
122 bfd_sess_set_vrf(adj->bfd_session,
123 adj->circuit->interface->vrf->vrf_id);
124 bfd_sess_set_profile(adj->bfd_session, circuit->bfd_config.profile);
125 bfd_sess_install(adj->bfd_session);
126 return;
127 out:
128 bfd_handle_adj_down(adj);
129 }
130
131 static int bfd_handle_adj_state_change(struct isis_adjacency *adj)
132 {
133 if (adj->adj_state == ISIS_ADJ_UP)
134 bfd_handle_adj_up(adj);
135 else
136 bfd_handle_adj_down(adj);
137 return 0;
138 }
139
140 static void bfd_adj_cmd(struct isis_adjacency *adj)
141 {
142 if (adj->adj_state == ISIS_ADJ_UP && adj->circuit->bfd_config.enabled)
143 bfd_handle_adj_up(adj);
144 else
145 bfd_handle_adj_down(adj);
146 }
147
148 void isis_bfd_circuit_cmd(struct isis_circuit *circuit)
149 {
150 switch (circuit->circ_type) {
151 case CIRCUIT_T_BROADCAST:
152 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
153 struct list *adjdb = circuit->u.bc.adjdb[level - 1];
154
155 struct listnode *node;
156 struct isis_adjacency *adj;
157
158 if (!adjdb)
159 continue;
160 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
161 bfd_adj_cmd(adj);
162 }
163 break;
164 case CIRCUIT_T_P2P:
165 if (circuit->u.p2p.neighbor)
166 bfd_adj_cmd(circuit->u.p2p.neighbor);
167 break;
168 default:
169 break;
170 }
171 }
172
173 static int bfd_handle_adj_ip_enabled(struct isis_adjacency *adj, int family,
174 bool global)
175 {
176
177 if (family != AF_INET6 || global)
178 return 0;
179
180 if (adj->bfd_session)
181 return 0;
182
183 if (adj->adj_state != ISIS_ADJ_UP)
184 return 0;
185
186 bfd_handle_adj_up(adj);
187
188 return 0;
189 }
190
191 static int bfd_handle_circuit_add_addr(struct isis_circuit *circuit)
192 {
193 struct isis_adjacency *adj;
194 struct listnode *node;
195
196 if (circuit->area == NULL)
197 return 0;
198
199 for (ALL_LIST_ELEMENTS_RO(circuit->area->adjacency_list, node, adj)) {
200 if (adj->bfd_session)
201 continue;
202
203 if (adj->adj_state != ISIS_ADJ_UP)
204 continue;
205
206 bfd_handle_adj_up(adj);
207 }
208
209 return 0;
210 }
211
212 void isis_bfd_init(struct event_loop *tm)
213 {
214 bfd_protocol_integration_init(zclient, tm);
215
216 hook_register(isis_adj_state_change_hook, bfd_handle_adj_state_change);
217 hook_register(isis_adj_ip_enabled_hook, bfd_handle_adj_ip_enabled);
218 hook_register(isis_circuit_add_addr_hook, bfd_handle_circuit_add_addr);
219 }