]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_bfd.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / isisd / isis_bfd.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
52df8228
CF
2/*
3 * IS-IS Rout(e)ing protocol - BFD support
52df8228 4 * Copyright (C) 2018 Christian Franke
52df8228
CF
5 */
6#include <zebra.h>
7
8#include "zclient.h"
e782cca7 9#include "nexthop.h"
52df8228 10#include "bfd.h"
e782cca7 11#include "lib_errors.h"
52df8228
CF
12
13#include "isisd/isis_bfd.h"
14#include "isisd/isis_zebra.h"
215eccb0
CF
15#include "isisd/isis_common.h"
16#include "isisd/isis_constants.h"
17#include "isisd/isis_adjacency.h"
18#include "isisd/isis_circuit.h"
3015e3d1 19#include "isisd/isisd.h"
215eccb0 20#include "isisd/fabricd.h"
52df8228 21
bf8d3d6a 22DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session");
20a42f01 23
13bf3830
IR
24static void adj_bfd_cb(struct bfd_session_params *bsp,
25 const struct bfd_session_status *bss, void *arg)
52df8228 26{
13bf3830 27 struct isis_adjacency *adj = arg;
ab880eaf 28
e740f9c1 29 if (IS_DEBUG_BFD)
13bf3830
IR
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));
bb99eb5d 35
13bf3830
IR
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");
bb99eb5d 41 }
bb99eb5d
G
42}
43
20a42f01
CF
44static void bfd_handle_adj_down(struct isis_adjacency *adj)
45{
13bf3830 46 bfd_sess_free(&adj->bfd_session);
20a42f01
CF
47}
48
13bf3830 49static void bfd_handle_adj_up(struct isis_adjacency *adj)
215eccb0 50{
20a42f01 51 struct isis_circuit *circuit = adj->circuit;
e782cca7
RW
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;
20a42f01 57
13bf3830 58 if (!circuit->bfd_config.enabled) {
980390ce
EDP
59 if (IS_DEBUG_BFD)
60 zlog_debug(
13bf3830 61 "ISIS-BFD: skipping BFD initialization on adjacency with %s because BFD is not enabled for the circuit",
980390ce 62 isis_adj_name(adj));
20a42f01 63 goto out;
980390ce 64 }
20a42f01 65
2bec0447
KS
66 /* If IS-IS IPv6 is configured wait for IPv6 address to be programmed
67 * before starting up BFD
68 */
0d5b1a3a
EDP
69 if (circuit->ipv6_router
70 && (listcount(circuit->ipv6_link) == 0
173f8887 71 || adj->ll_ipv6_count == 0)) {
0d5b1a3a
EDP
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));
2bec0447 76 return;
0d5b1a3a 77 }
2bec0447 78
e782cca7
RW
79 /*
80 * If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer
81 * creating a BFD session over IPv6.
82 */
173f8887 83 if (circuit->ipv6_router && adj->ll_ipv6_count) {
e782cca7 84 family = AF_INET6;
173f8887 85 dst_ip.ipv6 = adj->ll_ipv6_addrs[0];
e782cca7 86 local_ips = circuit->ipv6_link;
91a5bbc4 87 if (list_isempty(local_ips)) {
980390ce
EDP
88 if (IS_DEBUG_BFD)
89 zlog_debug(
90 "ISIS-BFD: skipping BFD initialization: IPv6 enabled and no local IPv6 addresses");
e782cca7 91 goto out;
980390ce 92 }
e782cca7
RW
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);
980390ce
EDP
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");
e782cca7 103 goto out;
980390ce 104 }
e782cca7
RW
105 local_ip = listgetdata(listhead(local_ips));
106 src_ip.ipv4 = local_ip->u.prefix4;
107 } else
20a42f01
CF
108 goto out;
109
13bf3830
IR
110 if (adj->bfd_session == NULL)
111 adj->bfd_session = bfd_sess_new(adj_bfd_cb, adj);
bb99eb5d 112
13bf3830
IR
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);
096f7609
IR
122 bfd_sess_set_vrf(adj->bfd_session,
123 adj->circuit->interface->vrf->vrf_id);
13bf3830
IR
124 bfd_sess_set_profile(adj->bfd_session, circuit->bfd_config.profile);
125 bfd_sess_install(adj->bfd_session);
215eccb0 126 return;
20a42f01
CF
127out:
128 bfd_handle_adj_down(adj);
129}
130
131static int bfd_handle_adj_state_change(struct isis_adjacency *adj)
132{
133 if (adj->adj_state == ISIS_ADJ_UP)
13bf3830 134 bfd_handle_adj_up(adj);
20a42f01
CF
135 else
136 bfd_handle_adj_down(adj);
137 return 0;
138}
139
13bf3830 140static void bfd_adj_cmd(struct isis_adjacency *adj)
20a42f01 141{
13bf3830
IR
142 if (adj->adj_state == ISIS_ADJ_UP && adj->circuit->bfd_config.enabled)
143 bfd_handle_adj_up(adj);
144 else
20a42f01 145 bfd_handle_adj_down(adj);
20a42f01
CF
146}
147
13bf3830 148void isis_bfd_circuit_cmd(struct isis_circuit *circuit)
20a42f01
CF
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;
5489eb45 157
a514ac48
PG
158 if (!adjdb)
159 continue;
20a42f01 160 for (ALL_LIST_ELEMENTS_RO(adjdb, node, adj))
13bf3830 161 bfd_adj_cmd(adj);
20a42f01
CF
162 }
163 break;
164 case CIRCUIT_T_P2P:
165 if (circuit->u.p2p.neighbor)
13bf3830 166 bfd_adj_cmd(circuit->u.p2p.neighbor);
20a42f01
CF
167 break;
168 default:
169 break;
170 }
215eccb0
CF
171}
172
173f8887
OD
173static int bfd_handle_adj_ip_enabled(struct isis_adjacency *adj, int family,
174 bool global)
2bec0447
KS
175{
176
173f8887 177 if (family != AF_INET6 || global)
2bec0447
KS
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
13bf3830 186 bfd_handle_adj_up(adj);
2bec0447
KS
187
188 return 0;
189}
190
191static int bfd_handle_circuit_add_addr(struct isis_circuit *circuit)
192{
193 struct isis_adjacency *adj;
194 struct listnode *node;
195
9d3de36d 196 if (circuit->area == NULL)
2bec0447
KS
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
13bf3830 206 bfd_handle_adj_up(adj);
2bec0447
KS
207 }
208
209 return 0;
210}
211
13bf3830 212void isis_bfd_init(struct thread_master *tm)
52df8228 213{
13bf3830
IR
214 bfd_protocol_integration_init(zclient, tm);
215
216 hook_register(isis_adj_state_change_hook, bfd_handle_adj_state_change);
2bec0447
KS
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);
52df8228 219}