]>
Commit | Line | Data |
---|---|---|
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 | 35 | DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session"); |
20a42f01 | 36 | |
13bf3830 IR |
37 | static 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 |
57 | static void bfd_handle_adj_down(struct isis_adjacency *adj) |
58 | { | |
13bf3830 | 59 | bfd_sess_free(&adj->bfd_session); |
20a42f01 CF |
60 | } |
61 | ||
13bf3830 | 62 | static 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; |
980390ce EDP |
100 | if (!local_ips || list_isempty(local_ips)) { |
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 |
140 | out: |
141 | bfd_handle_adj_down(adj); | |
142 | } | |
143 | ||
144 | static 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 | 153 | static 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 | 161 | void 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 |
186 | static 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 | ||
204 | static int bfd_handle_circuit_add_addr(struct isis_circuit *circuit) | |
205 | { | |
206 | struct isis_adjacency *adj; | |
207 | struct listnode *node; | |
208 | ||
209 | if (circuit->area == 0) | |
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 | 225 | void 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 | } |