]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_bfd.c
*: manual SPDX License ID conversions
[mirror_frr.git] / isisd / isis_bfd.c
CommitLineData
52df8228
CF
1/*
2 * IS-IS Rout(e)ing protocol - BFD support
52df8228
CF
3 * Copyright (C) 2018 Christian Franke
4 *
d04f9fbf
CF
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
52df8228 9 *
d04f9fbf
CF
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
52df8228
CF
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include <zebra.h>
20
21#include "zclient.h"
e782cca7 22#include "nexthop.h"
52df8228 23#include "bfd.h"
e782cca7 24#include "lib_errors.h"
52df8228
CF
25
26#include "isisd/isis_bfd.h"
27#include "isisd/isis_zebra.h"
215eccb0
CF
28#include "isisd/isis_common.h"
29#include "isisd/isis_constants.h"
30#include "isisd/isis_adjacency.h"
31#include "isisd/isis_circuit.h"
3015e3d1 32#include "isisd/isisd.h"
215eccb0 33#include "isisd/fabricd.h"
52df8228 34
bf8d3d6a 35DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session");
20a42f01 36
13bf3830
IR
37static void adj_bfd_cb(struct bfd_session_params *bsp,
38 const struct bfd_session_status *bss, void *arg)
52df8228 39{
13bf3830 40 struct isis_adjacency *adj = arg;
ab880eaf 41
e740f9c1 42 if (IS_DEBUG_BFD)
13bf3830
IR
43 zlog_debug(
44 "ISIS-BFD: BFD changed status for adjacency %s old %s new %s",
45 isis_adj_name(adj),
46 bfd_get_status_str(bss->previous_state),
47 bfd_get_status_str(bss->state));
bb99eb5d 48
13bf3830
IR
49 if (bss->state == BFD_STATUS_DOWN
50 && bss->previous_state == BFD_STATUS_UP) {
51 adj->circuit->area->bfd_signalled_down = true;
52 isis_adj_state_change(&adj, ISIS_ADJ_DOWN,
53 "bfd session went down");
bb99eb5d 54 }
bb99eb5d
G
55}
56
20a42f01
CF
57static void bfd_handle_adj_down(struct isis_adjacency *adj)
58{
13bf3830 59 bfd_sess_free(&adj->bfd_session);
20a42f01
CF
60}
61
13bf3830 62static void bfd_handle_adj_up(struct isis_adjacency *adj)
215eccb0 63{
20a42f01 64 struct isis_circuit *circuit = adj->circuit;
e782cca7
RW
65 int family;
66 union g_addr dst_ip;
67 union g_addr src_ip;
68 struct list *local_ips;
69 struct prefix *local_ip;
20a42f01 70
13bf3830 71 if (!circuit->bfd_config.enabled) {
980390ce
EDP
72 if (IS_DEBUG_BFD)
73 zlog_debug(
13bf3830 74 "ISIS-BFD: skipping BFD initialization on adjacency with %s because BFD is not enabled for the circuit",
980390ce 75 isis_adj_name(adj));
20a42f01 76 goto out;
980390ce 77 }
20a42f01 78
2bec0447
KS
79 /* If IS-IS IPv6 is configured wait for IPv6 address to be programmed
80 * before starting up BFD
81 */
0d5b1a3a
EDP
82 if (circuit->ipv6_router
83 && (listcount(circuit->ipv6_link) == 0
173f8887 84 || adj->ll_ipv6_count == 0)) {
0d5b1a3a
EDP
85 if (IS_DEBUG_BFD)
86 zlog_debug(
87 "ISIS-BFD: skipping BFD initialization on adjacency with %s because IPv6 is enabled but not ready",
88 isis_adj_name(adj));
2bec0447 89 return;
0d5b1a3a 90 }
2bec0447 91
e782cca7
RW
92 /*
93 * If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer
94 * creating a BFD session over IPv6.
95 */
173f8887 96 if (circuit->ipv6_router && adj->ll_ipv6_count) {
e782cca7 97 family = AF_INET6;
173f8887 98 dst_ip.ipv6 = adj->ll_ipv6_addrs[0];
e782cca7 99 local_ips = circuit->ipv6_link;
91a5bbc4 100 if (list_isempty(local_ips)) {
980390ce
EDP
101 if (IS_DEBUG_BFD)
102 zlog_debug(
103 "ISIS-BFD: skipping BFD initialization: IPv6 enabled and no local IPv6 addresses");
e782cca7 104 goto out;
980390ce 105 }
e782cca7
RW
106 local_ip = listgetdata(listhead(local_ips));
107 src_ip.ipv6 = local_ip->u.prefix6;
108 } else if (circuit->ip_router && adj->ipv4_address_count) {
109 family = AF_INET;
110 dst_ip.ipv4 = adj->ipv4_addresses[0];
111 local_ips = fabricd_ip_addrs(adj->circuit);
980390ce
EDP
112 if (!local_ips || list_isempty(local_ips)) {
113 if (IS_DEBUG_BFD)
114 zlog_debug(
115 "ISIS-BFD: skipping BFD initialization: IPv4 enabled and no local IPv4 addresses");
e782cca7 116 goto out;
980390ce 117 }
e782cca7
RW
118 local_ip = listgetdata(listhead(local_ips));
119 src_ip.ipv4 = local_ip->u.prefix4;
120 } else
20a42f01
CF
121 goto out;
122
13bf3830
IR
123 if (adj->bfd_session == NULL)
124 adj->bfd_session = bfd_sess_new(adj_bfd_cb, adj);
bb99eb5d 125
13bf3830
IR
126 bfd_sess_set_timers(adj->bfd_session, BFD_DEF_DETECT_MULT,
127 BFD_DEF_MIN_RX, BFD_DEF_MIN_TX);
128 if (family == AF_INET)
129 bfd_sess_set_ipv4_addrs(adj->bfd_session, &src_ip.ipv4,
130 &dst_ip.ipv4);
131 else
132 bfd_sess_set_ipv6_addrs(adj->bfd_session, &src_ip.ipv6,
133 &dst_ip.ipv6);
134 bfd_sess_set_interface(adj->bfd_session, adj->circuit->interface->name);
096f7609
IR
135 bfd_sess_set_vrf(adj->bfd_session,
136 adj->circuit->interface->vrf->vrf_id);
13bf3830
IR
137 bfd_sess_set_profile(adj->bfd_session, circuit->bfd_config.profile);
138 bfd_sess_install(adj->bfd_session);
215eccb0 139 return;
20a42f01
CF
140out:
141 bfd_handle_adj_down(adj);
142}
143
144static int bfd_handle_adj_state_change(struct isis_adjacency *adj)
145{
146 if (adj->adj_state == ISIS_ADJ_UP)
13bf3830 147 bfd_handle_adj_up(adj);
20a42f01
CF
148 else
149 bfd_handle_adj_down(adj);
150 return 0;
151}
152
13bf3830 153static void bfd_adj_cmd(struct isis_adjacency *adj)
20a42f01 154{
13bf3830
IR
155 if (adj->adj_state == ISIS_ADJ_UP && adj->circuit->bfd_config.enabled)
156 bfd_handle_adj_up(adj);
157 else
20a42f01 158 bfd_handle_adj_down(adj);
20a42f01
CF
159}
160
13bf3830 161void isis_bfd_circuit_cmd(struct isis_circuit *circuit)
20a42f01
CF
162{
163 switch (circuit->circ_type) {
164 case CIRCUIT_T_BROADCAST:
165 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
166 struct list *adjdb = circuit->u.bc.adjdb[level - 1];
167
168 struct listnode *node;
169 struct isis_adjacency *adj;
5489eb45 170
a514ac48
PG
171 if (!adjdb)
172 continue;
20a42f01 173 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
13bf3830 174 bfd_adj_cmd(adj);
20a42f01
CF
175 }
176 break;
177 case CIRCUIT_T_P2P:
178 if (circuit->u.p2p.neighbor)
13bf3830 179 bfd_adj_cmd(circuit->u.p2p.neighbor);
20a42f01
CF
180 break;
181 default:
182 break;
183 }
215eccb0
CF
184}
185
173f8887
OD
186static int bfd_handle_adj_ip_enabled(struct isis_adjacency *adj, int family,
187 bool global)
2bec0447
KS
188{
189
173f8887 190 if (family != AF_INET6 || global)
2bec0447
KS
191 return 0;
192
193 if (adj->bfd_session)
194 return 0;
195
196 if (adj->adj_state != ISIS_ADJ_UP)
197 return 0;
198
13bf3830 199 bfd_handle_adj_up(adj);
2bec0447
KS
200
201 return 0;
202}
203
204static int bfd_handle_circuit_add_addr(struct isis_circuit *circuit)
205{
206 struct isis_adjacency *adj;
207 struct listnode *node;
208
9d3de36d 209 if (circuit->area == NULL)
2bec0447
KS
210 return 0;
211
212 for (ALL_LIST_ELEMENTS_RO(circuit->area->adjacency_list, node, adj)) {
213 if (adj->bfd_session)
214 continue;
215
216 if (adj->adj_state != ISIS_ADJ_UP)
217 continue;
218
13bf3830 219 bfd_handle_adj_up(adj);
2bec0447
KS
220 }
221
222 return 0;
223}
224
13bf3830 225void isis_bfd_init(struct thread_master *tm)
52df8228 226{
13bf3830
IR
227 bfd_protocol_integration_init(zclient, tm);
228
229 hook_register(isis_adj_state_change_hook, bfd_handle_adj_state_change);
2bec0447
KS
230 hook_register(isis_adj_ip_enabled_hook, bfd_handle_adj_ip_enabled);
231 hook_register(isis_circuit_add_addr_hook, bfd_handle_circuit_add_addr);
52df8228 232}