]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
eb5d44eb | 2 | /* |
3 | * IS-IS Rout(e)ing protocol - isis_circuit.h | |
4 | * | |
5 | * Copyright (C) 2001,2002 Sampo Saaristo | |
d62a17ae | 6 | * Tampere University of Technology |
eb5d44eb | 7 | * Institute of Communications Engineering |
eb5d44eb | 8 | */ |
eb5d44eb | 9 | #include <zebra.h> |
37da8c01 | 10 | #ifdef GNU_LINUX |
eb5d44eb | 11 | #include <net/ethernet.h> |
37da8c01 | 12 | #else |
13 | #include <netinet/if_ether.h> | |
14 | #endif | |
eb5d44eb | 15 | |
16 | #include "log.h" | |
17 | #include "memory.h" | |
b2d7c082 | 18 | #include "vrf.h" |
eb5d44eb | 19 | #include "if.h" |
20 | #include "linklist.h" | |
21 | #include "command.h" | |
22 | #include "thread.h" | |
f8c06e2c | 23 | #include "vty.h" |
eb5d44eb | 24 | #include "hash.h" |
25 | #include "prefix.h" | |
26 | #include "stream.h" | |
676a4ea3 | 27 | #include "qobj.h" |
20600086 | 28 | #include "lib/northbound_cli.h" |
eb5d44eb | 29 | |
eb5d44eb | 30 | #include "isisd/isis_constants.h" |
31 | #include "isisd/isis_common.h" | |
3f045a08 | 32 | #include "isisd/isis_flags.h" |
eb5d44eb | 33 | #include "isisd/isis_circuit.h" |
eb5d44eb | 34 | #include "isisd/isis_lsp.h" |
35 | #include "isisd/isis_pdu.h" | |
36 | #include "isisd/isis_network.h" | |
37 | #include "isisd/isis_misc.h" | |
38 | #include "isisd/isis_constants.h" | |
39 | #include "isisd/isis_adjacency.h" | |
40 | #include "isisd/isis_dr.h" | |
eb5d44eb | 41 | #include "isisd/isisd.h" |
42 | #include "isisd/isis_csm.h" | |
43 | #include "isisd/isis_events.h" | |
f8c06e2c | 44 | #include "isisd/isis_te.h" |
064f4896 | 45 | #include "isisd/isis_mt.h" |
54ece698 | 46 | #include "isisd/isis_errors.h" |
9b39405f | 47 | #include "isisd/isis_tx_queue.h" |
2a1c520e | 48 | #include "isisd/isis_nb.h" |
1cbf96a8 | 49 | #include "isisd/isis_ldp_sync.h" |
eb5d44eb | 50 | |
66b9a381 DL |
51 | DEFINE_MTYPE_STATIC(ISISD, ISIS_CIRCUIT, "ISIS circuit"); |
52 | ||
96244aca | 53 | DEFINE_QOBJ_TYPE(isis_circuit); |
676a4ea3 | 54 | |
8451921b | 55 | DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)); |
ef7bd2a3 | 56 | |
41b36e90 PJ |
57 | /* |
58 | * Prototypes. | |
59 | */ | |
41b36e90 PJ |
60 | int isis_if_new_hook(struct interface *); |
61 | int isis_if_delete_hook(struct interface *); | |
62 | ||
e2b5b7d6 IR |
63 | DEFINE_HOOK(isis_circuit_new_hook, (struct isis_circuit *circuit), (circuit)); |
64 | DEFINE_HOOK(isis_circuit_del_hook, (struct isis_circuit *circuit), (circuit)); | |
1ee746d9 | 65 | |
bcf22081 IR |
66 | static void isis_circuit_enable(struct isis_circuit *circuit) |
67 | { | |
3ae43012 | 68 | struct isis_area *area = circuit->area; |
bcf22081 IR |
69 | struct interface *ifp = circuit->interface; |
70 | ||
3ae43012 | 71 | if (!area) { |
096f7609 | 72 | area = isis_area_lookup(circuit->tag, ifp->vrf->vrf_id); |
3ae43012 IR |
73 | if (area) |
74 | isis_area_add_circuit(area, circuit); | |
75 | } | |
bcf22081 IR |
76 | |
77 | if (if_is_operative(ifp)) | |
78 | isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp); | |
79 | } | |
80 | ||
81 | static void isis_circuit_disable(struct isis_circuit *circuit) | |
82 | { | |
83 | struct isis_area *area = circuit->area; | |
84 | struct interface *ifp = circuit->interface; | |
85 | ||
86 | if (if_is_operative(ifp)) | |
87 | isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp); | |
88 | ||
89 | if (area) | |
90 | isis_area_del_circuit(area, circuit); | |
91 | } | |
92 | ||
93 | struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag) | |
eb5d44eb | 94 | { |
d62a17ae | 95 | struct isis_circuit *circuit; |
96 | int i; | |
97 | ||
98 | circuit = XCALLOC(MTYPE_ISIS_CIRCUIT, sizeof(struct isis_circuit)); | |
d62a17ae | 99 | |
bcf22081 | 100 | circuit->tag = XSTRDUP(MTYPE_ISIS_CIRCUIT, tag); |
1ee746d9 | 101 | |
d62a17ae | 102 | /* |
103 | * Default values | |
104 | */ | |
cc50ddb2 | 105 | #ifndef FABRICD |
2f9a06f0 | 106 | circuit->is_type_config = yang_get_default_enum( |
cc50ddb2 EDP |
107 | "/frr-interface:lib/interface/frr-isisd:isis/circuit-type"); |
108 | circuit->flags = 0; | |
109 | ||
110 | circuit->pad_hellos = yang_get_default_bool( | |
111 | "/frr-interface:lib/interface/frr-isisd:isis/hello/padding"); | |
112 | circuit->hello_interval[0] = yang_get_default_uint32( | |
113 | "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-1"); | |
114 | circuit->hello_interval[1] = yang_get_default_uint32( | |
115 | "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-2"); | |
116 | circuit->hello_multiplier[0] = yang_get_default_uint32( | |
117 | "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-1"); | |
118 | circuit->hello_multiplier[1] = yang_get_default_uint32( | |
119 | "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-2"); | |
120 | circuit->csnp_interval[0] = yang_get_default_uint16( | |
121 | "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1"); | |
122 | circuit->csnp_interval[1] = yang_get_default_uint16( | |
123 | "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-2"); | |
124 | circuit->psnp_interval[0] = yang_get_default_uint16( | |
125 | "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-1"); | |
126 | circuit->psnp_interval[1] = yang_get_default_uint16( | |
127 | "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-2"); | |
128 | circuit->priority[0] = yang_get_default_uint8( | |
129 | "/frr-interface:lib/interface/frr-isisd:isis/priority/level-1"); | |
130 | circuit->priority[1] = yang_get_default_uint8( | |
131 | "/frr-interface:lib/interface/frr-isisd:isis/priority/level-2"); | |
132 | circuit->metric[0] = yang_get_default_uint32( | |
133 | "/frr-interface:lib/interface/frr-isisd:isis/metric/level-1"); | |
134 | circuit->metric[1] = yang_get_default_uint32( | |
135 | "/frr-interface:lib/interface/frr-isisd:isis/metric/level-2"); | |
136 | circuit->te_metric[0] = yang_get_default_uint32( | |
137 | "/frr-interface:lib/interface/frr-isisd:isis/metric/level-1"); | |
138 | circuit->te_metric[1] = yang_get_default_uint32( | |
139 | "/frr-interface:lib/interface/frr-isisd:isis/metric/level-2"); | |
140 | ||
141 | for (i = 0; i < 2; i++) { | |
142 | circuit->level_arg[i].level = i + 1; | |
143 | circuit->level_arg[i].circuit = circuit; | |
144 | } | |
145 | #else | |
2f9a06f0 | 146 | circuit->is_type_config = IS_LEVEL_1_AND_2; |
d62a17ae | 147 | circuit->flags = 0; |
148 | circuit->pad_hellos = 1; | |
149 | for (i = 0; i < 2; i++) { | |
150 | circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL; | |
151 | circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER; | |
152 | circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL; | |
153 | circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL; | |
154 | circuit->priority[i] = DEFAULT_PRIORITY; | |
155 | circuit->metric[i] = DEFAULT_CIRCUIT_METRIC; | |
156 | circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC; | |
7da4aa3c CF |
157 | circuit->level_arg[i].level = i + 1; |
158 | circuit->level_arg[i].circuit = circuit; | |
d62a17ae | 159 | } |
cc50ddb2 | 160 | #endif /* ifndef FABRICD */ |
d62a17ae | 161 | |
2f9a06f0 IR |
162 | circuit->is_type = circuit->is_type_config; |
163 | ||
d62a17ae | 164 | circuit_mt_init(circuit); |
e886416f RW |
165 | isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL1); |
166 | isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL2); | |
d62a17ae | 167 | |
ec62fbaa IR |
168 | circuit->ldp_sync_info = ldp_sync_info_create(); |
169 | circuit->ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED; | |
170 | ||
d62a17ae | 171 | QOBJ_REG(circuit, isis_circuit); |
172 | ||
bcf22081 IR |
173 | isis_circuit_if_bind(circuit, ifp); |
174 | ||
91a5bbc4 DS |
175 | circuit->ip_addrs = list_new(); |
176 | circuit->ipv6_link = list_new(); | |
177 | circuit->ipv6_non_link = list_new(); | |
178 | ||
bcf22081 IR |
179 | if (ifp->ifindex != IFINDEX_INTERNAL) |
180 | isis_circuit_enable(circuit); | |
181 | ||
d62a17ae | 182 | return circuit; |
eb5d44eb | 183 | } |
184 | ||
d62a17ae | 185 | void isis_circuit_del(struct isis_circuit *circuit) |
3f045a08 | 186 | { |
d62a17ae | 187 | if (!circuit) |
188 | return; | |
3f045a08 | 189 | |
bcf22081 IR |
190 | if (circuit->interface->ifindex != IFINDEX_INTERNAL) |
191 | isis_circuit_disable(circuit); | |
1ee746d9 | 192 | |
d62a17ae | 193 | isis_circuit_if_unbind(circuit, circuit->interface); |
3f045a08 | 194 | |
bcf22081 IR |
195 | QOBJ_UNREG(circuit); |
196 | ||
ec62fbaa IR |
197 | ldp_sync_info_free(&circuit->ldp_sync_info); |
198 | ||
d62a17ae | 199 | circuit_mt_finish(circuit); |
e886416f RW |
200 | isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL1); |
201 | isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL2); | |
064f4896 | 202 | |
91a5bbc4 DS |
203 | list_delete(&circuit->ip_addrs); |
204 | list_delete(&circuit->ipv6_link); | |
205 | list_delete(&circuit->ipv6_non_link); | |
206 | ||
1fa63850 OD |
207 | if (circuit->ext) { |
208 | isis_del_ext_subtlvs(circuit->ext); | |
209 | circuit->ext = NULL; | |
210 | } | |
211 | ||
13bf3830 | 212 | XFREE(MTYPE_TMP, circuit->bfd_config.profile); |
bcf22081 IR |
213 | XFREE(MTYPE_ISIS_CIRCUIT, circuit->tag); |
214 | ||
d62a17ae | 215 | /* and lastly the circuit itself */ |
216 | XFREE(MTYPE_ISIS_CIRCUIT, circuit); | |
3f045a08 | 217 | |
d62a17ae | 218 | return; |
3f045a08 JB |
219 | } |
220 | ||
d62a17ae | 221 | void isis_circuit_configure(struct isis_circuit *circuit, |
222 | struct isis_area *area) | |
eb5d44eb | 223 | { |
d62a17ae | 224 | assert(area); |
bcf22081 | 225 | circuit->isis = area->isis; |
d62a17ae | 226 | circuit->area = area; |
227 | ||
228 | /* | |
229 | * Whenever the is-type of an area is changed, the is-type of each | |
230 | * circuit | |
231 | * in that area is updated to a non-empty subset of the area is-type. | |
232 | * Inversely, when configuring a new circuit, this property should be | |
233 | * ensured as well. | |
234 | */ | |
235 | if (area->is_type != IS_LEVEL_1_AND_2) | |
236 | circuit->is_type = area->is_type; | |
237 | ||
238 | /* | |
239 | * Add the circuit into area | |
240 | */ | |
241 | listnode_add(area->circuit_list, circuit); | |
242 | ||
243 | circuit->idx = flags_get_index(&area->flags); | |
244 | ||
bcf22081 IR |
245 | hook_call(isis_circuit_new_hook, circuit); |
246 | ||
d62a17ae | 247 | return; |
eb5d44eb | 248 | } |
249 | ||
d62a17ae | 250 | void isis_circuit_deconfigure(struct isis_circuit *circuit, |
251 | struct isis_area *area) | |
eb5d44eb | 252 | { |
bcf22081 IR |
253 | hook_call(isis_circuit_del_hook, circuit); |
254 | ||
d62a17ae | 255 | /* Free the index of SRM and SSN flags */ |
256 | flags_free_index(&area->flags, circuit->idx); | |
257 | circuit->idx = 0; | |
2f9a06f0 IR |
258 | |
259 | /* Reset IS type to configured */ | |
260 | circuit->is_type = circuit->is_type_config; | |
261 | ||
d62a17ae | 262 | /* Remove circuit from area */ |
263 | assert(circuit->area == area); | |
264 | listnode_delete(area->circuit_list, circuit); | |
265 | circuit->area = NULL; | |
bcf22081 | 266 | circuit->isis = NULL; |
d62a17ae | 267 | |
268 | return; | |
eb5d44eb | 269 | } |
270 | ||
d62a17ae | 271 | struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp) |
eb5d44eb | 272 | { |
bcf22081 | 273 | return (struct isis_circuit *)ifp->info; |
eb5d44eb | 274 | } |
275 | ||
2bec0447 | 276 | DEFINE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit), |
8451921b | 277 | (circuit)); |
2bec0447 | 278 | |
d62a17ae | 279 | void isis_circuit_add_addr(struct isis_circuit *circuit, |
280 | struct connected *connected) | |
eb5d44eb | 281 | { |
d62a17ae | 282 | struct listnode *node; |
283 | struct prefix_ipv4 *ipv4; | |
d62a17ae | 284 | struct prefix_ipv6 *ipv6; |
f891f443 | 285 | |
d62a17ae | 286 | if (connected->address->family == AF_INET) { |
d7c0a89a | 287 | uint32_t addr = connected->address->u.prefix4.s_addr; |
d62a17ae | 288 | addr = ntohl(addr); |
289 | if (IPV4_NET0(addr) || IPV4_NET127(addr) || IN_CLASSD(addr) | |
290 | || IPV4_LINKLOCAL(addr)) | |
291 | return; | |
3f045a08 | 292 | |
d62a17ae | 293 | for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ipv4)) |
294 | if (prefix_same((struct prefix *)ipv4, | |
295 | connected->address)) | |
296 | return; | |
3f045a08 | 297 | |
d62a17ae | 298 | ipv4 = prefix_ipv4_new(); |
299 | ipv4->prefixlen = connected->address->prefixlen; | |
300 | ipv4->prefix = connected->address->u.prefix4; | |
301 | listnode_add(circuit->ip_addrs, ipv4); | |
f8c06e2c | 302 | |
1b3f47d0 | 303 | /* Update Local IP address parameter if MPLS TE is enable */ |
d80e23f8 EDP |
304 | if (circuit->ext && circuit->area |
305 | && IS_MPLS_TE(circuit->area->mta)) { | |
1b3f47d0 OD |
306 | circuit->ext->local_addr.s_addr = ipv4->prefix.s_addr; |
307 | SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR); | |
308 | } | |
f8c06e2c | 309 | |
d62a17ae | 310 | if (circuit->area) |
311 | lsp_regenerate_schedule(circuit->area, circuit->is_type, | |
312 | 0); | |
f891f443 | 313 | |
eb5d44eb | 314 | #ifdef EXTREME_DEBUG |
b0814935 PG |
315 | if (IS_DEBUG_EVENTS) |
316 | zlog_debug("Added IP address %pFX to circuit %s", | |
317 | connected->address, | |
318 | circuit->interface->name); | |
f390d2c7 | 319 | #endif /* EXTREME_DEBUG */ |
d62a17ae | 320 | } |
321 | if (connected->address->family == AF_INET6) { | |
322 | if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6)) | |
323 | return; | |
324 | ||
325 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ipv6)) | |
326 | if (prefix_same((struct prefix *)ipv6, | |
327 | connected->address)) | |
328 | return; | |
329 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ipv6)) | |
330 | if (prefix_same((struct prefix *)ipv6, | |
331 | connected->address)) | |
332 | return; | |
333 | ||
334 | ipv6 = prefix_ipv6_new(); | |
335 | ipv6->prefixlen = connected->address->prefixlen; | |
336 | ipv6->prefix = connected->address->u.prefix6; | |
337 | ||
338 | if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix)) | |
339 | listnode_add(circuit->ipv6_link, ipv6); | |
173f8887 | 340 | else { |
d62a17ae | 341 | listnode_add(circuit->ipv6_non_link, ipv6); |
173f8887 OD |
342 | /* Update Local IPv6 address param. if MPLS TE is on */ |
343 | if (circuit->ext && circuit->area | |
344 | && IS_MPLS_TE(circuit->area->mta)) { | |
345 | IPV6_ADDR_COPY(&circuit->ext->local_addr6, | |
346 | &ipv6->prefix); | |
347 | SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR6); | |
348 | } | |
349 | } | |
d62a17ae | 350 | if (circuit->area) |
351 | lsp_regenerate_schedule(circuit->area, circuit->is_type, | |
352 | 0); | |
f891f443 | 353 | |
eb5d44eb | 354 | #ifdef EXTREME_DEBUG |
b0814935 PG |
355 | if (IS_DEBUG_EVENTS) |
356 | zlog_debug("Added IPv6 address %pFX to circuit %s", | |
357 | connected->address, | |
358 | circuit->interface->name); | |
f390d2c7 | 359 | #endif /* EXTREME_DEBUG */ |
d62a17ae | 360 | } |
2bec0447 KS |
361 | |
362 | hook_call(isis_circuit_add_addr_hook, circuit); | |
363 | ||
d62a17ae | 364 | return; |
eb5d44eb | 365 | } |
366 | ||
d62a17ae | 367 | void isis_circuit_del_addr(struct isis_circuit *circuit, |
368 | struct connected *connected) | |
eb5d44eb | 369 | { |
d62a17ae | 370 | struct prefix_ipv4 *ipv4, *ip = NULL; |
371 | struct listnode *node; | |
d62a17ae | 372 | struct prefix_ipv6 *ipv6, *ip6 = NULL; |
373 | int found = 0; | |
374 | ||
375 | if (connected->address->family == AF_INET) { | |
376 | ipv4 = prefix_ipv4_new(); | |
377 | ipv4->prefixlen = connected->address->prefixlen; | |
378 | ipv4->prefix = connected->address->u.prefix4; | |
379 | ||
380 | for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ip)) | |
381 | if (prefix_same((struct prefix *)ip, | |
382 | (struct prefix *)ipv4)) | |
383 | break; | |
384 | ||
385 | if (ip) { | |
386 | listnode_delete(circuit->ip_addrs, ip); | |
63265b5c | 387 | prefix_ipv4_free(&ip); |
d62a17ae | 388 | if (circuit->area) |
389 | lsp_regenerate_schedule(circuit->area, | |
390 | circuit->is_type, 0); | |
391 | } else { | |
d62a17ae | 392 | zlog_warn( |
2dbe669b DA |
393 | "Nonexistent ip address %pFX removal attempt from circuit %s", |
394 | connected->address, circuit->interface->name); | |
d62a17ae | 395 | zlog_warn("Current ip addresses on %s:", |
396 | circuit->interface->name); | |
397 | for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, | |
398 | ip)) { | |
2dbe669b | 399 | zlog_warn(" %pFX", ip); |
d62a17ae | 400 | } |
401 | zlog_warn("End of addresses"); | |
402 | } | |
403 | ||
63265b5c | 404 | prefix_ipv4_free(&ipv4); |
f891f443 | 405 | } |
d62a17ae | 406 | if (connected->address->family == AF_INET6) { |
407 | ipv6 = prefix_ipv6_new(); | |
408 | ipv6->prefixlen = connected->address->prefixlen; | |
409 | ipv6->prefix = connected->address->u.prefix6; | |
410 | ||
411 | if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix)) { | |
412 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, | |
413 | ip6)) { | |
414 | if (prefix_same((struct prefix *)ip6, | |
415 | (struct prefix *)ipv6)) | |
416 | break; | |
417 | } | |
418 | if (ip6) { | |
419 | listnode_delete(circuit->ipv6_link, ip6); | |
63265b5c | 420 | prefix_ipv6_free(&ip6); |
d62a17ae | 421 | found = 1; |
422 | } | |
423 | } else { | |
424 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, | |
425 | ip6)) { | |
426 | if (prefix_same((struct prefix *)ip6, | |
427 | (struct prefix *)ipv6)) | |
428 | break; | |
429 | } | |
430 | if (ip6) { | |
431 | listnode_delete(circuit->ipv6_non_link, ip6); | |
63265b5c | 432 | prefix_ipv6_free(&ip6); |
d62a17ae | 433 | found = 1; |
434 | } | |
435 | } | |
436 | ||
437 | if (!found) { | |
d62a17ae | 438 | zlog_warn( |
2dbe669b DA |
439 | "Nonexistent ip address %pFX removal attempt from circuit %s", |
440 | connected->address, circuit->interface->name); | |
d62a17ae | 441 | zlog_warn("Current ip addresses on %s:", |
442 | circuit->interface->name); | |
443 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, | |
2dbe669b DA |
444 | ip6)) |
445 | zlog_warn(" %pFX", (struct prefix *)ip6); | |
d62a17ae | 446 | zlog_warn(" -----"); |
447 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, | |
2dbe669b DA |
448 | ip6)) |
449 | zlog_warn(" %pFX", (struct prefix *)ip6); | |
d62a17ae | 450 | zlog_warn("End of addresses"); |
451 | } else if (circuit->area) | |
452 | lsp_regenerate_schedule(circuit->area, circuit->is_type, | |
453 | 0); | |
454 | ||
63265b5c | 455 | prefix_ipv6_free(&ipv6); |
f891f443 | 456 | } |
d62a17ae | 457 | return; |
458 | } | |
e8aca32f | 459 | |
0849c75e | 460 | static uint8_t isis_circuit_id_gen(struct isis *isis, struct interface *ifp) |
d62a17ae | 461 | { |
068c8222 CF |
462 | /* Circuit ids MUST be unique for any broadcast circuits. Otherwise, |
463 | * Pseudo-Node LSPs cannot be generated correctly. | |
464 | * | |
98c5bc15 | 465 | * Currently, allocate one circuit ID for any circuit, limiting the total |
068c8222 CF |
466 | * numer of circuits IS-IS can run on to 255. |
467 | * | |
98c5bc15 | 468 | * We should revisit this when implementing 3-way adjacencies for p2p, since |
068c8222 CF |
469 | * we then have extended interface IDs available. |
470 | */ | |
471 | uint8_t id = ifp->ifindex; | |
d62a17ae | 472 | unsigned int i; |
d62a17ae | 473 | |
068c8222 CF |
474 | for (i = 0; i < 256; i++) { |
475 | if (id && !_ISIS_CHECK_FLAG(isis->circuit_ids_used, id)) | |
d62a17ae | 476 | break; |
068c8222 | 477 | id++; |
f891f443 | 478 | } |
479 | ||
068c8222 | 480 | if (i == 256) { |
996c9314 LB |
481 | zlog_warn("Could not allocate a circuit id for '%s'", |
482 | ifp->name); | |
068c8222 | 483 | return 0; |
f891f443 | 484 | } |
e8aca32f | 485 | |
0849c75e | 486 | _ISIS_SET_FLAG(isis->circuit_ids_used, id); |
d62a17ae | 487 | return id; |
3f045a08 JB |
488 | } |
489 | ||
d62a17ae | 490 | void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp) |
eb5d44eb | 491 | { |
d62a17ae | 492 | struct listnode *node, *nnode; |
493 | struct connected *conn; | |
494 | ||
d62a17ae | 495 | if (if_is_broadcast(ifp)) { |
65f18157 | 496 | if (fabricd || circuit->circ_type_config == CIRCUIT_T_P2P) |
d62a17ae | 497 | circuit->circ_type = CIRCUIT_T_P2P; |
498 | else | |
499 | circuit->circ_type = CIRCUIT_T_BROADCAST; | |
500 | } else if (if_is_pointopoint(ifp)) { | |
501 | circuit->circ_type = CIRCUIT_T_P2P; | |
608c8870 | 502 | } else if (if_is_loopback(ifp)) { |
d62a17ae | 503 | circuit->circ_type = CIRCUIT_T_LOOPBACK; |
504 | circuit->is_passive = 1; | |
505 | } else { | |
506 | /* It's normal in case of loopback etc. */ | |
e740f9c1 | 507 | if (IS_DEBUG_EVENTS) |
1f46f33f | 508 | zlog_debug("%s: unsupported media", __func__); |
d62a17ae | 509 | circuit->circ_type = CIRCUIT_T_UNKNOWN; |
510 | } | |
511 | ||
d62a17ae | 512 | for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn)) |
513 | isis_circuit_add_addr(circuit, conn); | |
1b3f47d0 | 514 | |
eb5d44eb | 515 | } |
516 | ||
d62a17ae | 517 | void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp) |
eb5d44eb | 518 | { |
d62a17ae | 519 | struct listnode *node, *nnode; |
520 | struct connected *conn; | |
521 | ||
522 | assert(circuit->interface == ifp); | |
523 | ||
524 | /* destroy addresses */ | |
525 | for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn)) | |
526 | isis_circuit_del_addr(circuit, conn); | |
527 | ||
d62a17ae | 528 | circuit->circ_type = CIRCUIT_T_UNKNOWN; |
eb5d44eb | 529 | } |
530 | ||
d62a17ae | 531 | void isis_circuit_if_bind(struct isis_circuit *circuit, struct interface *ifp) |
3f045a08 | 532 | { |
d62a17ae | 533 | assert(circuit != NULL); |
534 | assert(ifp != NULL); | |
535 | if (circuit->interface) | |
536 | assert(circuit->interface == ifp); | |
537 | else | |
538 | circuit->interface = ifp; | |
539 | if (ifp->info) | |
540 | assert(ifp->info == circuit); | |
541 | else | |
542 | ifp->info = circuit; | |
3f045a08 JB |
543 | } |
544 | ||
d62a17ae | 545 | void isis_circuit_if_unbind(struct isis_circuit *circuit, struct interface *ifp) |
eb5d44eb | 546 | { |
d62a17ae | 547 | assert(circuit != NULL); |
548 | assert(ifp != NULL); | |
549 | assert(circuit->interface == ifp); | |
550 | assert(ifp->info == circuit); | |
551 | circuit->interface = NULL; | |
552 | ifp->info = NULL; | |
3f045a08 | 553 | } |
f390d2c7 | 554 | |
d62a17ae | 555 | static void isis_circuit_update_all_srmflags(struct isis_circuit *circuit, |
556 | int is_set) | |
3f045a08 | 557 | { |
d62a17ae | 558 | struct isis_area *area; |
559 | struct isis_lsp *lsp; | |
d62a17ae | 560 | int level; |
561 | ||
562 | assert(circuit); | |
563 | area = circuit->area; | |
564 | assert(area); | |
565 | for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { | |
9b39405f CF |
566 | if (!(level & circuit->is_type)) |
567 | continue; | |
568 | ||
4bef0ec4 | 569 | if (!lspdb_count(&area->lspdb[level - 1])) |
9b39405f CF |
570 | continue; |
571 | ||
81fddbe7 | 572 | frr_each (lspdb, &area->lspdb[level - 1], lsp) { |
9b39405f CF |
573 | if (is_set) { |
574 | isis_tx_queue_add(circuit->tx_queue, lsp, | |
575 | TX_LSP_NORMAL); | |
576 | } else { | |
577 | isis_tx_queue_del(circuit->tx_queue, lsp); | |
d62a17ae | 578 | } |
579 | } | |
580 | } | |
eb5d44eb | 581 | } |
582 | ||
d62a17ae | 583 | size_t isis_circuit_pdu_size(struct isis_circuit *circuit) |
b20ccb3a | 584 | { |
d62a17ae | 585 | return ISO_MTU(circuit); |
b20ccb3a CF |
586 | } |
587 | ||
694fa867 LS |
588 | static bool isis_circuit_lfa_enabled(struct isis_circuit *circuit, int level) |
589 | { | |
590 | return (circuit->lfa_protection[level - 1] || | |
591 | circuit->rlfa_protection[level - 1] || | |
592 | circuit->tilfa_protection[level - 1]); | |
593 | } | |
594 | ||
595 | void isis_circuit_switchover_routes(struct isis_circuit *circuit, int family, | |
596 | union g_addr *nexthop_ip, ifindex_t ifindex) | |
597 | { | |
598 | char is_type; | |
599 | ||
600 | if (!circuit->area) | |
601 | return; | |
602 | ||
603 | is_type = circuit->area->is_type; | |
604 | if ((is_type == IS_LEVEL_1 || is_type == IS_LEVEL_1_AND_2) && | |
605 | isis_circuit_lfa_enabled(circuit, IS_LEVEL_1)) | |
606 | isis_area_switchover_routes(circuit->area, family, nexthop_ip, | |
607 | ifindex, IS_LEVEL_1); | |
608 | if ((is_type == IS_LEVEL_2 || is_type == IS_LEVEL_1_AND_2) && | |
609 | isis_circuit_lfa_enabled(circuit, IS_LEVEL_2)) | |
610 | isis_area_switchover_routes(circuit->area, family, nexthop_ip, | |
611 | ifindex, IS_LEVEL_2); | |
612 | } | |
613 | ||
d62a17ae | 614 | void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream) |
b20ccb3a | 615 | { |
d62a17ae | 616 | size_t stream_size = isis_circuit_pdu_size(circuit); |
617 | ||
618 | if (!*stream) { | |
619 | *stream = stream_new(stream_size); | |
620 | } else { | |
621 | if (STREAM_SIZE(*stream) != stream_size) | |
db3c830a | 622 | stream_resize_inplace(stream, stream_size); |
d62a17ae | 623 | stream_reset(*stream); |
624 | } | |
b20ccb3a CF |
625 | } |
626 | ||
d62a17ae | 627 | void isis_circuit_prepare(struct isis_circuit *circuit) |
5904f19f | 628 | { |
b0dd98e7 | 629 | #if ISIS_METHOD != ISIS_METHOD_DLPI |
d62a17ae | 630 | thread_add_read(master, isis_receive, circuit, circuit->fd, |
631 | &circuit->t_read); | |
5904f19f | 632 | #else |
d62a17ae | 633 | thread_add_timer_msec(master, isis_receive, circuit, |
634 | listcount(circuit->area->circuit_list) * 100, | |
635 | &circuit->t_read); | |
5904f19f RW |
636 | #endif |
637 | } | |
638 | ||
d62a17ae | 639 | int isis_circuit_up(struct isis_circuit *circuit) |
eb5d44eb | 640 | { |
d62a17ae | 641 | int retv; |
642 | ||
643 | /* Set the flags for all the lsps of the circuit. */ | |
644 | isis_circuit_update_all_srmflags(circuit, 1); | |
645 | ||
646 | if (circuit->state == C_STATE_UP) | |
647 | return ISIS_OK; | |
648 | ||
93bdc367 | 649 | if (circuit->is_passive) { |
1ee746d9 | 650 | circuit->last_uptime = time(NULL); |
93bdc367 EDP |
651 | /* make sure the union fields are initialized, else we |
652 | * could end with garbage values from a previous circuit | |
653 | * type, which would then cause a segfault when building | |
654 | * LSPs or computing the SPF tree | |
655 | */ | |
656 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
657 | circuit->u.bc.adjdb[0] = list_new(); | |
658 | circuit->u.bc.adjdb[1] = list_new(); | |
659 | } else if (circuit->circ_type == CIRCUIT_T_P2P) { | |
660 | circuit->u.p2p.neighbor = NULL; | |
661 | } | |
d62a17ae | 662 | return ISIS_OK; |
93bdc367 | 663 | } |
d62a17ae | 664 | |
665 | if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit)) { | |
af4c2728 | 666 | flog_err( |
1a7ecb96 | 667 | EC_ISIS_CONFIG, |
d62a17ae | 668 | "Interface MTU %zu on %s is too low to support area lsp mtu %u!", |
669 | isis_circuit_pdu_size(circuit), | |
670 | circuit->interface->name, circuit->area->lsp_mtu); | |
c7b253d0 | 671 | |
672 | /* Allow ISIS to continue configuration. With this | |
673 | * configuration failure ISIS will attempt to send lsp | |
674 | * packets but will fail until the mtu is configured properly | |
675 | */ | |
d62a17ae | 676 | } |
677 | ||
678 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
99e5d4af DS |
679 | circuit->circuit_id = |
680 | isis_circuit_id_gen(circuit->isis, circuit->interface); | |
0849c75e | 681 | if (!circuit->circuit_id) { |
af4c2728 | 682 | flog_err( |
1a7ecb96 | 683 | EC_ISIS_CONFIG, |
54ece698 | 684 | "There are already 255 broadcast circuits active!"); |
0849c75e CF |
685 | return ISIS_ERROR; |
686 | } | |
687 | ||
d62a17ae | 688 | /* |
689 | * Get the Hardware Address | |
690 | */ | |
691 | if (circuit->interface->hw_addr_len != ETH_ALEN) { | |
692 | zlog_warn("unsupported link layer"); | |
693 | } else { | |
694 | memcpy(circuit->u.bc.snpa, circuit->interface->hw_addr, | |
695 | ETH_ALEN); | |
696 | } | |
3f045a08 | 697 | #ifdef EXTREME_DEGUG |
b0814935 | 698 | if (IS_DEBUG_EVENTS) |
1f46f33f | 699 | zlog_debug("%s: if_id %d, isomtu %d snpa %s", __func__, |
700 | circuit->interface->ifindex, | |
701 | ISO_MTU(circuit), | |
702 | snpa_print(circuit->u.bc.snpa)); | |
3f045a08 | 703 | #endif /* EXTREME_DEBUG */ |
3f045a08 | 704 | |
d62a17ae | 705 | circuit->u.bc.adjdb[0] = list_new(); |
706 | circuit->u.bc.adjdb[1] = list_new(); | |
707 | ||
708 | /* | |
709 | * ISO 10589 - 8.4.1 Enabling of broadcast circuits | |
710 | */ | |
711 | ||
712 | /* initilizing the hello sending threads | |
713 | * for a broadcast IF | |
714 | */ | |
715 | ||
716 | /* 8.4.1 a) commence sending of IIH PDUs */ | |
717 | ||
7c4f7aab CF |
718 | for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { |
719 | if (!(circuit->is_type & level)) | |
720 | continue; | |
721 | ||
a0a707ee | 722 | send_hello_sched(circuit, level, TRIGGERED_IIH_DELAY); |
7c4f7aab CF |
723 | circuit->u.bc.lan_neighs[level - 1] = list_new(); |
724 | ||
725 | thread_add_timer(master, isis_run_dr, | |
726 | &circuit->level_arg[level - 1], | |
727 | 2 * circuit->hello_interval[level - 1], | |
728 | &circuit->u.bc.t_run_dr[level - 1]); | |
d62a17ae | 729 | } |
730 | ||
731 | /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */ | |
732 | /* 8.4.1 c) FIXME: listen for ESH PDUs */ | |
d4670f51 | 733 | } else if (circuit->circ_type == CIRCUIT_T_P2P) { |
d62a17ae | 734 | /* initializing the hello send threads |
735 | * for a ptp IF | |
736 | */ | |
737 | circuit->u.p2p.neighbor = NULL; | |
a0a707ee | 738 | send_hello_sched(circuit, 0, TRIGGERED_IIH_DELAY); |
d62a17ae | 739 | } |
740 | ||
741 | /* initializing PSNP timers */ | |
742 | if (circuit->is_type & IS_LEVEL_1) | |
743 | thread_add_timer( | |
744 | master, send_l1_psnp, circuit, | |
745 | isis_jitter(circuit->psnp_interval[0], PSNP_JITTER), | |
746 | &circuit->t_send_psnp[0]); | |
747 | ||
748 | if (circuit->is_type & IS_LEVEL_2) | |
749 | thread_add_timer( | |
750 | master, send_l2_psnp, circuit, | |
751 | isis_jitter(circuit->psnp_interval[1], PSNP_JITTER), | |
752 | &circuit->t_send_psnp[1]); | |
753 | ||
754 | /* unified init for circuits; ignore warnings below this level */ | |
755 | retv = isis_sock_init(circuit); | |
756 | if (retv != ISIS_OK) { | |
757 | isis_circuit_down(circuit); | |
758 | return retv; | |
759 | } | |
760 | ||
761 | /* initialize the circuit streams after opening connection */ | |
762 | isis_circuit_stream(circuit, &circuit->rcv_stream); | |
763 | isis_circuit_stream(circuit, &circuit->snd_stream); | |
764 | ||
765 | isis_circuit_prepare(circuit); | |
766 | ||
9b39405f | 767 | circuit->tx_queue = isis_tx_queue_new(circuit, send_lsp); |
d62a17ae | 768 | |
1ee746d9 | 769 | circuit->last_uptime = time(NULL); |
770 | ||
0fdd8b2b IR |
771 | if (circuit->area->mta && circuit->area->mta->status) |
772 | isis_link_params_update(circuit, circuit->interface); | |
773 | ||
ec62fbaa IR |
774 | isis_if_ldp_sync_enable(circuit); |
775 | ||
392b89f3 EDP |
776 | #ifndef FABRICD |
777 | /* send northbound notification */ | |
778 | isis_notif_if_state_change(circuit, false); | |
779 | #endif /* ifndef FABRICD */ | |
780 | ||
d62a17ae | 781 | return ISIS_OK; |
eb5d44eb | 782 | } |
783 | ||
d62a17ae | 784 | void isis_circuit_down(struct isis_circuit *circuit) |
eb5d44eb | 785 | { |
392b89f3 EDP |
786 | #ifndef FABRICD |
787 | /* send northbound notification */ | |
788 | isis_notif_if_state_change(circuit, true); | |
789 | #endif /* ifndef FABRICD */ | |
790 | ||
ec62fbaa IR |
791 | isis_if_ldp_sync_disable(circuit); |
792 | ||
7145d5bb | 793 | /* log adjacency changes if configured to do so */ |
5e69d308 | 794 | if (circuit->area->log_adj_changes) { |
7145d5bb EDP |
795 | struct isis_adjacency *adj = NULL; |
796 | if (circuit->circ_type == CIRCUIT_T_P2P) { | |
797 | adj = circuit->u.p2p.neighbor; | |
798 | if (adj) | |
799 | isis_log_adj_change( | |
800 | adj, adj->adj_state, ISIS_ADJ_DOWN, | |
801 | "circuit is being brought down"); | |
802 | } else if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
803 | struct list *adj_list; | |
804 | struct listnode *node; | |
805 | if (circuit->u.bc.adjdb[0]) { | |
806 | adj_list = list_new(); | |
807 | isis_adj_build_up_list(circuit->u.bc.adjdb[0], | |
808 | adj_list); | |
809 | for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) | |
810 | isis_log_adj_change( | |
811 | adj, adj->adj_state, | |
812 | ISIS_ADJ_DOWN, | |
813 | "circuit is being brought down"); | |
814 | list_delete(&adj_list); | |
815 | } | |
816 | if (circuit->u.bc.adjdb[1]) { | |
817 | adj_list = list_new(); | |
818 | isis_adj_build_up_list(circuit->u.bc.adjdb[1], | |
819 | adj_list); | |
820 | for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) | |
821 | isis_log_adj_change( | |
822 | adj, adj->adj_state, | |
823 | ISIS_ADJ_DOWN, | |
824 | "circuit is being brought down"); | |
825 | list_delete(&adj_list); | |
826 | } | |
827 | } | |
828 | } | |
829 | ||
d62a17ae | 830 | /* Clear the flags for all the lsps of the circuit. */ |
831 | isis_circuit_update_all_srmflags(circuit, 0); | |
832 | ||
833 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
834 | /* destroy neighbour lists */ | |
835 | if (circuit->u.bc.lan_neighs[0]) { | |
6a154c88 | 836 | list_delete(&circuit->u.bc.lan_neighs[0]); |
d62a17ae | 837 | circuit->u.bc.lan_neighs[0] = NULL; |
838 | } | |
839 | if (circuit->u.bc.lan_neighs[1]) { | |
6a154c88 | 840 | list_delete(&circuit->u.bc.lan_neighs[1]); |
d62a17ae | 841 | circuit->u.bc.lan_neighs[1] = NULL; |
842 | } | |
843 | /* destroy adjacency databases */ | |
844 | if (circuit->u.bc.adjdb[0]) { | |
845 | circuit->u.bc.adjdb[0]->del = isis_delete_adj; | |
6a154c88 | 846 | list_delete(&circuit->u.bc.adjdb[0]); |
d62a17ae | 847 | circuit->u.bc.adjdb[0] = NULL; |
848 | } | |
849 | if (circuit->u.bc.adjdb[1]) { | |
850 | circuit->u.bc.adjdb[1]->del = isis_delete_adj; | |
6a154c88 | 851 | list_delete(&circuit->u.bc.adjdb[1]); |
d62a17ae | 852 | circuit->u.bc.adjdb[1] = NULL; |
853 | } | |
854 | if (circuit->u.bc.is_dr[0]) { | |
855 | isis_dr_resign(circuit, 1); | |
856 | circuit->u.bc.is_dr[0] = 0; | |
857 | } | |
858 | memset(circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1); | |
859 | if (circuit->u.bc.is_dr[1]) { | |
860 | isis_dr_resign(circuit, 2); | |
861 | circuit->u.bc.is_dr[1] = 0; | |
862 | } | |
863 | memset(circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1); | |
864 | memset(circuit->u.bc.snpa, 0, ETH_ALEN); | |
865 | ||
fa935aa7 DS |
866 | THREAD_OFF(circuit->u.bc.t_send_lan_hello[0]); |
867 | THREAD_OFF(circuit->u.bc.t_send_lan_hello[1]); | |
868 | THREAD_OFF(circuit->u.bc.t_run_dr[0]); | |
869 | THREAD_OFF(circuit->u.bc.t_run_dr[1]); | |
870 | THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[0]); | |
871 | THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[1]); | |
d62a17ae | 872 | circuit->lsp_regenerate_pending[0] = 0; |
873 | circuit->lsp_regenerate_pending[1] = 0; | |
0849c75e | 874 | |
99e5d4af | 875 | _ISIS_CLEAR_FLAG(circuit->isis->circuit_ids_used, |
eab88f36 | 876 | circuit->circuit_id); |
0849c75e | 877 | circuit->circuit_id = 0; |
d62a17ae | 878 | } else if (circuit->circ_type == CIRCUIT_T_P2P) { |
879 | isis_delete_adj(circuit->u.p2p.neighbor); | |
880 | circuit->u.p2p.neighbor = NULL; | |
fa935aa7 | 881 | THREAD_OFF(circuit->u.p2p.t_send_p2p_hello); |
d62a17ae | 882 | } |
883 | ||
1ee746d9 | 884 | /* |
885 | * All adjacencies have to be gone, delete snmp list | |
886 | * and reset snmpd idx generator | |
887 | */ | |
888 | if (circuit->snmp_adj_list != NULL) | |
889 | list_delete(&circuit->snmp_adj_list); | |
890 | ||
891 | circuit->snmp_adj_idx_gen = 0; | |
892 | ||
d62a17ae | 893 | /* Cancel all active threads */ |
fa935aa7 DS |
894 | THREAD_OFF(circuit->t_send_csnp[0]); |
895 | THREAD_OFF(circuit->t_send_csnp[1]); | |
896 | THREAD_OFF(circuit->t_send_psnp[0]); | |
897 | THREAD_OFF(circuit->t_send_psnp[1]); | |
898 | THREAD_OFF(circuit->t_read); | |
d62a17ae | 899 | |
9b39405f CF |
900 | if (circuit->tx_queue) { |
901 | isis_tx_queue_free(circuit->tx_queue); | |
902 | circuit->tx_queue = NULL; | |
58e16237 CF |
903 | } |
904 | ||
d62a17ae | 905 | /* send one gratuitous hello to spead up convergence */ |
d4670f51 CF |
906 | if (circuit->state == C_STATE_UP) { |
907 | if (circuit->is_type & IS_LEVEL_1) | |
908 | send_hello(circuit, IS_LEVEL_1); | |
909 | if (circuit->is_type & IS_LEVEL_2) | |
910 | send_hello(circuit, IS_LEVEL_2); | |
911 | } | |
d62a17ae | 912 | |
913 | circuit->upadjcount[0] = 0; | |
914 | circuit->upadjcount[1] = 0; | |
915 | ||
916 | /* close the socket */ | |
917 | if (circuit->fd) { | |
918 | close(circuit->fd); | |
919 | circuit->fd = 0; | |
920 | } | |
921 | ||
922 | if (circuit->rcv_stream != NULL) { | |
923 | stream_free(circuit->rcv_stream); | |
924 | circuit->rcv_stream = NULL; | |
925 | } | |
926 | ||
927 | if (circuit->snd_stream != NULL) { | |
928 | stream_free(circuit->snd_stream); | |
929 | circuit->snd_stream = NULL; | |
930 | } | |
931 | ||
932 | thread_cancel_event(master, circuit); | |
933 | ||
934 | return; | |
eb5d44eb | 935 | } |
936 | ||
d62a17ae | 937 | void circuit_update_nlpids(struct isis_circuit *circuit) |
eb5d44eb | 938 | { |
d62a17ae | 939 | circuit->nlpids.count = 0; |
940 | ||
941 | if (circuit->ip_router) { | |
942 | circuit->nlpids.nlpids[0] = NLPID_IP; | |
943 | circuit->nlpids.count++; | |
944 | } | |
945 | if (circuit->ipv6_router) { | |
946 | circuit->nlpids.nlpids[circuit->nlpids.count] = NLPID_IPV6; | |
947 | circuit->nlpids.count++; | |
948 | } | |
949 | return; | |
eb5d44eb | 950 | } |
951 | ||
9fee4d4c JG |
952 | void isis_circuit_print_json(struct isis_circuit *circuit, |
953 | struct json_object *json, char detail) | |
954 | { | |
955 | int level; | |
956 | json_object *iface_json, *ipv4_addr_json, *ipv6_link_json, | |
957 | *ipv6_non_link_json, *hold_json, *lan_prio_json, *levels_json, | |
958 | *level_json; | |
959 | char buf_prx[INET6_BUFSIZ]; | |
960 | char buf[255]; | |
961 | ||
962 | snprintfrr(buf, sizeof(buf), "0x%x", circuit->circuit_id); | |
963 | if (detail == ISIS_UI_LEVEL_BRIEF) { | |
964 | iface_json = json_object_new_object(); | |
965 | json_object_object_add(json, "interface", iface_json); | |
966 | json_object_string_add(iface_json, "name", | |
967 | circuit->interface->name); | |
968 | json_object_string_add(iface_json, "circuit-id", buf); | |
969 | json_object_string_add(iface_json, "state", | |
970 | circuit_state2string(circuit->state)); | |
971 | json_object_string_add(iface_json, "type", | |
972 | circuit_type2string(circuit->circ_type)); | |
973 | json_object_string_add(iface_json, "level", | |
974 | circuit_t2string(circuit->is_type)); | |
975 | } | |
976 | ||
977 | if (detail == ISIS_UI_LEVEL_DETAIL) { | |
978 | struct listnode *node; | |
979 | struct prefix *ip_addr; | |
980 | ||
981 | iface_json = json_object_new_object(); | |
982 | json_object_object_add(json, "interface", iface_json); | |
983 | json_object_string_add(iface_json, "name", | |
984 | circuit->interface->name); | |
985 | json_object_string_add(iface_json, "state", | |
986 | circuit_state2string(circuit->state)); | |
987 | if (circuit->is_passive) | |
988 | json_object_string_add(iface_json, "is-passive", | |
989 | "passive"); | |
990 | else | |
991 | json_object_string_add(iface_json, "is-passive", | |
992 | "active"); | |
993 | json_object_string_add(iface_json, "circuit-id", buf); | |
994 | json_object_string_add(iface_json, "type", | |
995 | circuit_type2string(circuit->circ_type)); | |
996 | json_object_string_add(iface_json, "level", | |
997 | circuit_t2string(circuit->is_type)); | |
998 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) | |
999 | json_object_string_add(iface_json, "snpa", | |
1000 | snpa_print(circuit->u.bc.snpa)); | |
1001 | ||
1002 | ||
1003 | levels_json = json_object_new_array(); | |
1004 | json_object_object_add(iface_json, "levels", levels_json); | |
1005 | for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { | |
1006 | if ((circuit->is_type & level) == 0) | |
1007 | continue; | |
1008 | level_json = json_object_new_object(); | |
1009 | json_object_string_add(level_json, "level", | |
1010 | circuit_t2string(level)); | |
1011 | if (circuit->area->newmetric) | |
1012 | json_object_int_add(level_json, "metric", | |
1013 | circuit->te_metric[0]); | |
1014 | else | |
1015 | json_object_int_add(level_json, "metric", | |
1016 | circuit->metric[0]); | |
1017 | if (!circuit->is_passive) { | |
1018 | json_object_int_add(level_json, | |
1019 | "active-neighbors", | |
1020 | circuit->upadjcount[0]); | |
1021 | json_object_int_add(level_json, | |
1022 | "hello-interval", | |
1023 | circuit->hello_interval[0]); | |
1024 | hold_json = json_object_new_object(); | |
1025 | json_object_object_add(level_json, "holddown", | |
1026 | hold_json); | |
1027 | json_object_int_add( | |
1028 | hold_json, "count", | |
1029 | circuit->hello_multiplier[0]); | |
1030 | json_object_string_add( | |
1031 | hold_json, "pad", | |
1032 | (circuit->pad_hellos ? "yes" : "no")); | |
1033 | json_object_int_add(level_json, "cnsp-interval", | |
1034 | circuit->csnp_interval[0]); | |
1035 | json_object_int_add(level_json, "psnp-interval", | |
1036 | circuit->psnp_interval[0]); | |
1037 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
1038 | lan_prio_json = | |
1039 | json_object_new_object(); | |
1040 | json_object_object_add(level_json, | |
1041 | "lan", | |
1042 | lan_prio_json); | |
1043 | json_object_int_add( | |
1044 | lan_prio_json, "priority", | |
1045 | circuit->priority[0]); | |
1046 | json_object_string_add( | |
1047 | lan_prio_json, "is-dis", | |
1048 | (circuit->u.bc.is_dr[0] | |
1049 | ? "yes" | |
1050 | : "no")); | |
1051 | } | |
1052 | } | |
1053 | json_object_array_add(levels_json, level_json); | |
1054 | } | |
1055 | ||
91a5bbc4 | 1056 | if (listcount(circuit->ip_addrs) > 0) { |
9fee4d4c JG |
1057 | ipv4_addr_json = json_object_new_object(); |
1058 | json_object_object_add(iface_json, "ip-prefix", | |
1059 | ipv4_addr_json); | |
1060 | for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, | |
1061 | ip_addr)) { | |
1062 | snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", | |
1063 | ip_addr); | |
1064 | json_object_string_add(ipv4_addr_json, "ip", | |
1065 | buf_prx); | |
1066 | } | |
1067 | } | |
91a5bbc4 | 1068 | if (listcount(circuit->ipv6_link) > 0) { |
9fee4d4c JG |
1069 | ipv6_link_json = json_object_new_object(); |
1070 | json_object_object_add(iface_json, "ipv6-link-locals", | |
1071 | ipv6_link_json); | |
1072 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, | |
1073 | ip_addr)) { | |
1074 | snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", | |
1075 | ip_addr); | |
1076 | json_object_string_add(ipv6_link_json, "ipv6", | |
1077 | buf_prx); | |
1078 | } | |
1079 | } | |
91a5bbc4 | 1080 | if (listcount(circuit->ipv6_non_link) > 0) { |
9fee4d4c JG |
1081 | ipv6_non_link_json = json_object_new_object(); |
1082 | json_object_object_add(iface_json, "ipv6-prefixes", | |
1083 | ipv6_non_link_json); | |
1084 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, | |
1085 | ip_addr)) { | |
1086 | snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", | |
1087 | ip_addr); | |
1088 | json_object_string_add(ipv6_non_link_json, | |
1089 | "ipv6", buf_prx); | |
1090 | } | |
1091 | } | |
1092 | } | |
1093 | return; | |
1094 | } | |
1095 | ||
d62a17ae | 1096 | void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty, |
1097 | char detail) | |
3f045a08 | 1098 | { |
d62a17ae | 1099 | if (detail == ISIS_UI_LEVEL_BRIEF) { |
1100 | vty_out(vty, " %-12s", circuit->interface->name); | |
1101 | vty_out(vty, "0x%-7x", circuit->circuit_id); | |
1102 | vty_out(vty, "%-9s", circuit_state2string(circuit->state)); | |
1103 | vty_out(vty, "%-9s", circuit_type2string(circuit->circ_type)); | |
1104 | vty_out(vty, "%-9s", circuit_t2string(circuit->is_type)); | |
1105 | vty_out(vty, "\n"); | |
1106 | } | |
1107 | ||
1108 | if (detail == ISIS_UI_LEVEL_DETAIL) { | |
1109 | struct listnode *node; | |
1110 | struct prefix *ip_addr; | |
d62a17ae | 1111 | |
1112 | vty_out(vty, " Interface: %s", circuit->interface->name); | |
1113 | vty_out(vty, ", State: %s", | |
1114 | circuit_state2string(circuit->state)); | |
1115 | if (circuit->is_passive) | |
1116 | vty_out(vty, ", Passive"); | |
1117 | else | |
1118 | vty_out(vty, ", Active"); | |
1119 | vty_out(vty, ", Circuit Id: 0x%x", circuit->circuit_id); | |
1120 | vty_out(vty, "\n"); | |
1121 | vty_out(vty, " Type: %s", | |
1122 | circuit_type2string(circuit->circ_type)); | |
1123 | vty_out(vty, ", Level: %s", circuit_t2string(circuit->is_type)); | |
1124 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) | |
1125 | vty_out(vty, ", SNPA: %-10s", | |
1126 | snpa_print(circuit->u.bc.snpa)); | |
1127 | vty_out(vty, "\n"); | |
1128 | if (circuit->is_type & IS_LEVEL_1) { | |
1129 | vty_out(vty, " Level-1 Information:\n"); | |
1130 | if (circuit->area->newmetric) | |
1131 | vty_out(vty, " Metric: %d", | |
1132 | circuit->te_metric[0]); | |
1133 | else | |
1134 | vty_out(vty, " Metric: %d", | |
1135 | circuit->metric[0]); | |
1136 | if (!circuit->is_passive) { | |
1137 | vty_out(vty, ", Active neighbors: %u\n", | |
1138 | circuit->upadjcount[0]); | |
1139 | vty_out(vty, | |
3efd0893 | 1140 | " Hello interval: %u, Holddown count: %u %s\n", |
d62a17ae | 1141 | circuit->hello_interval[0], |
1142 | circuit->hello_multiplier[0], | |
1143 | (circuit->pad_hellos ? "(pad)" | |
1144 | : "(no-pad)")); | |
1145 | vty_out(vty, | |
3efd0893 | 1146 | " CNSP interval: %u, PSNP interval: %u\n", |
d62a17ae | 1147 | circuit->csnp_interval[0], |
1148 | circuit->psnp_interval[0]); | |
1149 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) | |
1150 | vty_out(vty, | |
1151 | " LAN Priority: %u, %s\n", | |
1152 | circuit->priority[0], | |
1153 | (circuit->u.bc.is_dr[0] | |
1154 | ? "is DIS" | |
1155 | : "is not DIS")); | |
1156 | } else { | |
1157 | vty_out(vty, "\n"); | |
1158 | } | |
1159 | } | |
1160 | if (circuit->is_type & IS_LEVEL_2) { | |
1161 | vty_out(vty, " Level-2 Information:\n"); | |
1162 | if (circuit->area->newmetric) | |
1163 | vty_out(vty, " Metric: %d", | |
1164 | circuit->te_metric[1]); | |
1165 | else | |
1166 | vty_out(vty, " Metric: %d", | |
1167 | circuit->metric[1]); | |
1168 | if (!circuit->is_passive) { | |
1169 | vty_out(vty, ", Active neighbors: %u\n", | |
1170 | circuit->upadjcount[1]); | |
1171 | vty_out(vty, | |
3efd0893 | 1172 | " Hello interval: %u, Holddown count: %u %s\n", |
d62a17ae | 1173 | circuit->hello_interval[1], |
1174 | circuit->hello_multiplier[1], | |
1175 | (circuit->pad_hellos ? "(pad)" | |
1176 | : "(no-pad)")); | |
1177 | vty_out(vty, | |
3efd0893 | 1178 | " CNSP interval: %u, PSNP interval: %u\n", |
d62a17ae | 1179 | circuit->csnp_interval[1], |
1180 | circuit->psnp_interval[1]); | |
1181 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) | |
1182 | vty_out(vty, | |
1183 | " LAN Priority: %u, %s\n", | |
1184 | circuit->priority[1], | |
1185 | (circuit->u.bc.is_dr[1] | |
1186 | ? "is DIS" | |
1187 | : "is not DIS")); | |
1188 | } else { | |
1189 | vty_out(vty, "\n"); | |
1190 | } | |
1191 | } | |
91a5bbc4 | 1192 | if (listcount(circuit->ip_addrs) > 0) { |
d62a17ae | 1193 | vty_out(vty, " IP Prefix(es):\n"); |
1194 | for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, | |
2dbe669b DA |
1195 | ip_addr)) |
1196 | vty_out(vty, " %pFX\n", ip_addr); | |
d62a17ae | 1197 | } |
91a5bbc4 | 1198 | if (listcount(circuit->ipv6_link) > 0) { |
d62a17ae | 1199 | vty_out(vty, " IPv6 Link-Locals:\n"); |
1200 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, | |
2dbe669b DA |
1201 | ip_addr)) |
1202 | vty_out(vty, " %pFX\n", ip_addr); | |
d62a17ae | 1203 | } |
91a5bbc4 | 1204 | if (listcount(circuit->ipv6_non_link) > 0) { |
d62a17ae | 1205 | vty_out(vty, " IPv6 Prefixes:\n"); |
1206 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, | |
2dbe669b DA |
1207 | ip_addr)) |
1208 | vty_out(vty, " %pFX\n", ip_addr); | |
d62a17ae | 1209 | } |
1210 | ||
1211 | vty_out(vty, "\n"); | |
1212 | } | |
1213 | return; | |
3f045a08 JB |
1214 | } |
1215 | ||
05e4ec37 | 1216 | #ifdef FABRICD |
d56afe53 CF |
1217 | DEFINE_HOOK(isis_circuit_config_write, |
1218 | (struct isis_circuit *circuit, struct vty *vty), | |
8451921b | 1219 | (circuit, vty)); |
d56afe53 | 1220 | |
612c2c15 | 1221 | static int isis_interface_config_write(struct vty *vty) |
eb5d44eb | 1222 | { |
f4e14fdb | 1223 | struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); |
d62a17ae | 1224 | int write = 0; |
d62a17ae | 1225 | struct interface *ifp; |
d62a17ae | 1226 | struct isis_circuit *circuit; |
1227 | int i; | |
1228 | ||
451fda4f | 1229 | FOR_ALL_INTERFACES (vrf, ifp) { |
d62a17ae | 1230 | /* IF name */ |
788a036f | 1231 | if_vty_config_start(vty, ifp); |
d62a17ae | 1232 | write++; |
1233 | /* IF desc */ | |
1234 | if (ifp->desc) { | |
1235 | vty_out(vty, " description %s\n", ifp->desc); | |
1236 | write++; | |
1237 | } | |
1238 | /* ISIS Circuit */ | |
88ae0963 IR |
1239 | do { |
1240 | circuit = circuit_scan_by_ifp(ifp); | |
d62a17ae | 1241 | if (circuit == NULL) |
88ae0963 | 1242 | break; |
d62a17ae | 1243 | if (circuit->ip_router) { |
7c0cbd0e | 1244 | vty_out(vty, " ip router " PROTO_NAME " %s\n", |
88ae0963 | 1245 | circuit->tag); |
d62a17ae | 1246 | write++; |
1247 | } | |
1248 | if (circuit->is_passive) { | |
7c0cbd0e | 1249 | vty_out(vty, " " PROTO_NAME " passive\n"); |
d62a17ae | 1250 | write++; |
1251 | } | |
1252 | if (circuit->circ_type_config == CIRCUIT_T_P2P) { | |
7c0cbd0e | 1253 | vty_out(vty, " " PROTO_NAME " network point-to-point\n"); |
d62a17ae | 1254 | write++; |
1255 | } | |
1256 | if (circuit->ipv6_router) { | |
7c0cbd0e | 1257 | vty_out(vty, " ipv6 router " PROTO_NAME " %s\n", |
88ae0963 | 1258 | circuit->tag); |
d62a17ae | 1259 | write++; |
1260 | } | |
1261 | ||
1262 | /* ISIS - circuit type */ | |
65f18157 CF |
1263 | if (!fabricd) { |
1264 | if (circuit->is_type == IS_LEVEL_1) { | |
1265 | vty_out(vty, " " PROTO_NAME " circuit-type level-1\n"); | |
d62a17ae | 1266 | write++; |
65f18157 CF |
1267 | } else { |
1268 | if (circuit->is_type == IS_LEVEL_2) { | |
1269 | vty_out(vty, | |
1270 | " " PROTO_NAME " circuit-type level-2-only\n"); | |
1271 | write++; | |
1272 | } | |
d62a17ae | 1273 | } |
1274 | } | |
1275 | ||
1276 | /* ISIS - CSNP interval */ | |
1277 | if (circuit->csnp_interval[0] | |
1278 | == circuit->csnp_interval[1]) { | |
1279 | if (circuit->csnp_interval[0] | |
1280 | != DEFAULT_CSNP_INTERVAL) { | |
7c0cbd0e | 1281 | vty_out(vty, " " PROTO_NAME " csnp-interval %d\n", |
d62a17ae | 1282 | circuit->csnp_interval[0]); |
1283 | write++; | |
1284 | } | |
1285 | } else { | |
1286 | for (i = 0; i < 2; i++) { | |
1287 | if (circuit->csnp_interval[i] | |
1288 | != DEFAULT_CSNP_INTERVAL) { | |
1289 | vty_out(vty, | |
7c0cbd0e | 1290 | " " PROTO_NAME " csnp-interval %d level-%d\n", |
d62a17ae | 1291 | circuit->csnp_interval |
1292 | [i], | |
1293 | i + 1); | |
1294 | write++; | |
1295 | } | |
1296 | } | |
1297 | } | |
1298 | ||
1299 | /* ISIS - PSNP interval */ | |
1300 | if (circuit->psnp_interval[0] | |
1301 | == circuit->psnp_interval[1]) { | |
1302 | if (circuit->psnp_interval[0] | |
1303 | != DEFAULT_PSNP_INTERVAL) { | |
7c0cbd0e | 1304 | vty_out(vty, " " PROTO_NAME " psnp-interval %d\n", |
d62a17ae | 1305 | circuit->psnp_interval[0]); |
1306 | write++; | |
1307 | } | |
1308 | } else { | |
1309 | for (i = 0; i < 2; i++) { | |
1310 | if (circuit->psnp_interval[i] | |
1311 | != DEFAULT_PSNP_INTERVAL) { | |
1312 | vty_out(vty, | |
7c0cbd0e | 1313 | " " PROTO_NAME " psnp-interval %d level-%d\n", |
d62a17ae | 1314 | circuit->psnp_interval |
1315 | [i], | |
1316 | i + 1); | |
1317 | write++; | |
1318 | } | |
1319 | } | |
1320 | } | |
1321 | ||
1322 | /* ISIS - Hello padding - Defaults to true so only | |
1323 | * display if false */ | |
1324 | if (circuit->pad_hellos == 0) { | |
7c0cbd0e | 1325 | vty_out(vty, " no " PROTO_NAME " hello padding\n"); |
d62a17ae | 1326 | write++; |
1327 | } | |
1328 | ||
58e5d748 CF |
1329 | if (circuit->disable_threeway_adj) { |
1330 | vty_out(vty, " no isis three-way-handshake\n"); | |
1331 | write++; | |
1332 | } | |
1333 | ||
d62a17ae | 1334 | /* ISIS - Hello interval */ |
1335 | if (circuit->hello_interval[0] | |
1336 | == circuit->hello_interval[1]) { | |
1337 | if (circuit->hello_interval[0] | |
1338 | != DEFAULT_HELLO_INTERVAL) { | |
1339 | vty_out(vty, | |
7c0cbd0e | 1340 | " " PROTO_NAME " hello-interval %d\n", |
d62a17ae | 1341 | circuit->hello_interval[0]); |
1342 | write++; | |
1343 | } | |
1344 | } else { | |
1345 | for (i = 0; i < 2; i++) { | |
1346 | if (circuit->hello_interval[i] | |
1347 | != DEFAULT_HELLO_INTERVAL) { | |
1348 | vty_out(vty, | |
7c0cbd0e | 1349 | " " PROTO_NAME " hello-interval %d level-%d\n", |
d62a17ae | 1350 | circuit->hello_interval |
1351 | [i], | |
1352 | i + 1); | |
1353 | write++; | |
1354 | } | |
1355 | } | |
1356 | } | |
1357 | ||
1358 | /* ISIS - Hello Multiplier */ | |
1359 | if (circuit->hello_multiplier[0] | |
1360 | == circuit->hello_multiplier[1]) { | |
1361 | if (circuit->hello_multiplier[0] | |
1362 | != DEFAULT_HELLO_MULTIPLIER) { | |
1363 | vty_out(vty, | |
7c0cbd0e | 1364 | " " PROTO_NAME " hello-multiplier %d\n", |
d62a17ae | 1365 | circuit->hello_multiplier[0]); |
1366 | write++; | |
1367 | } | |
1368 | } else { | |
1369 | for (i = 0; i < 2; i++) { | |
1370 | if (circuit->hello_multiplier[i] | |
1371 | != DEFAULT_HELLO_MULTIPLIER) { | |
1372 | vty_out(vty, | |
7c0cbd0e | 1373 | " " PROTO_NAME " hello-multiplier %d level-%d\n", |
d62a17ae | 1374 | circuit->hello_multiplier |
1375 | [i], | |
1376 | i + 1); | |
1377 | write++; | |
1378 | } | |
1379 | } | |
1380 | } | |
1381 | ||
1382 | /* ISIS - Priority */ | |
1383 | if (circuit->priority[0] == circuit->priority[1]) { | |
1384 | if (circuit->priority[0] != DEFAULT_PRIORITY) { | |
7c0cbd0e | 1385 | vty_out(vty, " " PROTO_NAME " priority %d\n", |
d62a17ae | 1386 | circuit->priority[0]); |
1387 | write++; | |
1388 | } | |
1389 | } else { | |
1390 | for (i = 0; i < 2; i++) { | |
1391 | if (circuit->priority[i] | |
1392 | != DEFAULT_PRIORITY) { | |
1393 | vty_out(vty, | |
7c0cbd0e | 1394 | " " PROTO_NAME " priority %d level-%d\n", |
d62a17ae | 1395 | circuit->priority[i], |
1396 | i + 1); | |
1397 | write++; | |
1398 | } | |
1399 | } | |
1400 | } | |
1401 | ||
1402 | /* ISIS - Metric */ | |
1403 | if (circuit->te_metric[0] == circuit->te_metric[1]) { | |
1404 | if (circuit->te_metric[0] | |
1405 | != DEFAULT_CIRCUIT_METRIC) { | |
7c0cbd0e | 1406 | vty_out(vty, " " PROTO_NAME " metric %d\n", |
d62a17ae | 1407 | circuit->te_metric[0]); |
1408 | write++; | |
1409 | } | |
1410 | } else { | |
1411 | for (i = 0; i < 2; i++) { | |
1412 | if (circuit->te_metric[i] | |
1413 | != DEFAULT_CIRCUIT_METRIC) { | |
1414 | vty_out(vty, | |
7c0cbd0e | 1415 | " " PROTO_NAME " metric %d level-%d\n", |
d62a17ae | 1416 | circuit->te_metric[i], |
1417 | i + 1); | |
1418 | write++; | |
1419 | } | |
1420 | } | |
1421 | } | |
1422 | if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { | |
7c0cbd0e | 1423 | vty_out(vty, " " PROTO_NAME " password md5 %s\n", |
d62a17ae | 1424 | circuit->passwd.passwd); |
1425 | write++; | |
1426 | } else if (circuit->passwd.type | |
1427 | == ISIS_PASSWD_TYPE_CLEARTXT) { | |
7c0cbd0e | 1428 | vty_out(vty, " " PROTO_NAME " password clear %s\n", |
d62a17ae | 1429 | circuit->passwd.passwd); |
1430 | write++; | |
1431 | } | |
13bf3830 IR |
1432 | if (circuit->bfd_config.enabled) { |
1433 | vty_out(vty, " " PROTO_NAME " bfd\n"); | |
1434 | write++; | |
1435 | } | |
5489eb45 CF |
1436 | write += hook_call(isis_circuit_config_write, |
1437 | circuit, vty); | |
88ae0963 | 1438 | } while (0); |
788a036f | 1439 | if_vty_config_end(vty); |
d62a17ae | 1440 | } |
1441 | ||
1442 | return write; | |
eb5d44eb | 1443 | } |
20600086 | 1444 | #endif /* ifdef FABRICD */ |
eb5d44eb | 1445 | |
d62a17ae | 1446 | void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router, |
1447 | bool ipv6_router) | |
eb5d44eb | 1448 | { |
d62a17ae | 1449 | struct isis_area *area = circuit->area; |
e8cff6d1 EDP |
1450 | int old_ipr = circuit->ip_router; |
1451 | int old_ipv6r = circuit->ipv6_router; | |
1452 | ||
1453 | /* is there something to do? */ | |
1454 | if (old_ipr == ip_router && old_ipv6r == ipv6_router) | |
1455 | return; | |
d62a17ae | 1456 | |
d62a17ae | 1457 | circuit->ip_router = ip_router; |
1458 | circuit->ipv6_router = ipv6_router; | |
e8cff6d1 | 1459 | circuit_update_nlpids(circuit); |
d62a17ae | 1460 | |
bcf22081 IR |
1461 | if (area) { |
1462 | area->ip_circuits += ip_router - old_ipr; | |
1463 | area->ipv6_circuits += ipv6_router - old_ipv6r; | |
d62a17ae | 1464 | |
bcf22081 IR |
1465 | if (ip_router || ipv6_router) |
1466 | lsp_regenerate_schedule(area, circuit->is_type, 0); | |
1467 | } | |
3f045a08 | 1468 | } |
eb5d44eb | 1469 | |
64dd3ffe | 1470 | ferr_r isis_circuit_passive_set(struct isis_circuit *circuit, bool passive) |
3f045a08 | 1471 | { |
d62a17ae | 1472 | if (circuit->is_passive == passive) |
64dd3ffe | 1473 | return ferr_ok(); |
d62a17ae | 1474 | |
608c8870 | 1475 | if (if_is_loopback(circuit->interface) && !passive) |
64dd3ffe | 1476 | return ferr_cfg_invalid("loopback is always passive"); |
d62a17ae | 1477 | |
1478 | if (circuit->state != C_STATE_UP) { | |
1479 | circuit->is_passive = passive; | |
1480 | } else { | |
1481 | struct isis_area *area = circuit->area; | |
1482 | isis_csm_state_change(ISIS_DISABLE, circuit, area); | |
1483 | circuit->is_passive = passive; | |
1484 | isis_csm_state_change(ISIS_ENABLE, circuit, area); | |
1485 | } | |
1486 | ||
64dd3ffe | 1487 | return ferr_ok(); |
eb5d44eb | 1488 | } |
1489 | ||
64dd3ffe DL |
1490 | ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level, |
1491 | int metric) | |
3f045a08 | 1492 | { |
d62a17ae | 1493 | assert(level == IS_LEVEL_1 || level == IS_LEVEL_2); |
1494 | if (metric > MAX_WIDE_LINK_METRIC) | |
64dd3ffe DL |
1495 | return ferr_cfg_invalid("metric %d too large for wide metric", |
1496 | metric); | |
d62a17ae | 1497 | if (circuit->area && circuit->area->oldmetric |
1498 | && metric > MAX_NARROW_LINK_METRIC) | |
64dd3ffe DL |
1499 | return ferr_cfg_invalid("metric %d too large for narrow metric", |
1500 | metric); | |
d62a17ae | 1501 | |
1cbf96a8 | 1502 | /* inform ldp-sync of metric change |
1503 | * if ldp-sync is running need to save metric | |
1504 | * and restore new values after ldp-sync completion. | |
1505 | */ | |
1506 | if (isis_ldp_sync_if_metric_config(circuit, level, metric)) { | |
1507 | circuit->te_metric[level - 1] = metric; | |
1508 | circuit->metric[level - 1] = metric; | |
1509 | if (circuit->area) | |
1510 | lsp_regenerate_schedule(circuit->area, level, 0); | |
1511 | } | |
64dd3ffe | 1512 | return ferr_ok(); |
eb5d44eb | 1513 | } |
1514 | ||
64dd3ffe | 1515 | ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit) |
eb5d44eb | 1516 | { |
d62a17ae | 1517 | memset(&circuit->passwd, 0, sizeof(circuit->passwd)); |
64dd3ffe | 1518 | return ferr_ok(); |
3f045a08 JB |
1519 | } |
1520 | ||
e28544ed QY |
1521 | ferr_r isis_circuit_passwd_set(struct isis_circuit *circuit, |
1522 | uint8_t passwd_type, const char *passwd) | |
3f045a08 | 1523 | { |
d62a17ae | 1524 | int len; |
f390d2c7 | 1525 | |
d62a17ae | 1526 | if (!passwd) |
64dd3ffe | 1527 | return ferr_code_bug("no circuit password given"); |
50c7d14a | 1528 | |
d62a17ae | 1529 | len = strlen(passwd); |
1530 | if (len > 254) | |
64dd3ffe DL |
1531 | return ferr_code_bug( |
1532 | "circuit password too long (max 254 chars)"); | |
f390d2c7 | 1533 | |
d62a17ae | 1534 | circuit->passwd.len = len; |
e28544ed QY |
1535 | strlcpy((char *)circuit->passwd.passwd, passwd, |
1536 | sizeof(circuit->passwd.passwd)); | |
d62a17ae | 1537 | circuit->passwd.type = passwd_type; |
64dd3ffe | 1538 | return ferr_ok(); |
eb5d44eb | 1539 | } |
1540 | ||
64dd3ffe DL |
1541 | ferr_r isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit, |
1542 | const char *passwd) | |
eb5d44eb | 1543 | { |
d62a17ae | 1544 | return isis_circuit_passwd_set(circuit, ISIS_PASSWD_TYPE_CLEARTXT, |
1545 | passwd); | |
50c7d14a | 1546 | } |
f390d2c7 | 1547 | |
64dd3ffe DL |
1548 | ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit, |
1549 | const char *passwd) | |
50c7d14a | 1550 | { |
d62a17ae | 1551 | return isis_circuit_passwd_set(circuit, ISIS_PASSWD_TYPE_HMAC_MD5, |
1552 | passwd); | |
eb5d44eb | 1553 | } |
64dd3ffe | 1554 | |
d0820765 | 1555 | void isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type) |
3f045a08 | 1556 | { |
64dd3ffe | 1557 | if (circuit->circ_type == circ_type) |
d0820765 | 1558 | return; |
d62a17ae | 1559 | |
d62a17ae | 1560 | if (circuit->state != C_STATE_UP) { |
1561 | circuit->circ_type = circ_type; | |
1562 | circuit->circ_type_config = circ_type; | |
1563 | } else { | |
1564 | struct isis_area *area = circuit->area; | |
d62a17ae | 1565 | |
1566 | isis_csm_state_change(ISIS_DISABLE, circuit, area); | |
1567 | circuit->circ_type = circ_type; | |
1568 | circuit->circ_type_config = circ_type; | |
1569 | isis_csm_state_change(ISIS_ENABLE, circuit, area); | |
1570 | } | |
3f045a08 JB |
1571 | } |
1572 | ||
d62a17ae | 1573 | int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid, |
1574 | bool enabled) | |
064f4896 | 1575 | { |
d62a17ae | 1576 | struct isis_circuit_mt_setting *setting; |
064f4896 | 1577 | |
d62a17ae | 1578 | setting = circuit_get_mt_setting(circuit, mtid); |
1579 | if (setting->enabled != enabled) { | |
1580 | setting->enabled = enabled; | |
bcf22081 IR |
1581 | if (circuit->area) |
1582 | lsp_regenerate_schedule(circuit->area, | |
1583 | IS_LEVEL_1 | IS_LEVEL_2, 0); | |
d62a17ae | 1584 | } |
064f4896 | 1585 | |
d62a17ae | 1586 | return CMD_SUCCESS; |
064f4896 CF |
1587 | } |
1588 | ||
d62a17ae | 1589 | int isis_if_new_hook(struct interface *ifp) |
eb5d44eb | 1590 | { |
d62a17ae | 1591 | return 0; |
eb5d44eb | 1592 | } |
1593 | ||
d62a17ae | 1594 | int isis_if_delete_hook(struct interface *ifp) |
eb5d44eb | 1595 | { |
bcf22081 IR |
1596 | if (ifp->info) |
1597 | isis_circuit_del(ifp->info); | |
d62a17ae | 1598 | |
1599 | return 0; | |
eb5d44eb | 1600 | } |
1601 | ||
138c5a74 DS |
1602 | static int isis_ifp_create(struct interface *ifp) |
1603 | { | |
bcf22081 IR |
1604 | struct isis_circuit *circuit = ifp->info; |
1605 | ||
1606 | if (circuit) | |
1607 | isis_circuit_enable(circuit); | |
65251ce8 | 1608 | |
ef7bd2a3 DS |
1609 | hook_call(isis_if_new_hook, ifp); |
1610 | ||
138c5a74 DS |
1611 | return 0; |
1612 | } | |
1613 | ||
1614 | static int isis_ifp_up(struct interface *ifp) | |
1615 | { | |
bcf22081 IR |
1616 | struct isis_circuit *circuit = ifp->info; |
1617 | ||
4e689dcd LS |
1618 | if (circuit) { |
1619 | UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z); | |
bcf22081 | 1620 | isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp); |
4e689dcd | 1621 | } |
ddbf3e60 | 1622 | |
138c5a74 DS |
1623 | return 0; |
1624 | } | |
1625 | ||
1626 | static int isis_ifp_down(struct interface *ifp) | |
1627 | { | |
0e83283c | 1628 | afi_t afi; |
bcf22081 IR |
1629 | struct isis_circuit *circuit = ifp->info; |
1630 | ||
0cd33c98 LS |
1631 | if (circuit && |
1632 | !CHECK_FLAG(circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z)) { | |
4e689dcd | 1633 | SET_FLAG(circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z); |
0e83283c LS |
1634 | for (afi = AFI_IP; afi <= AFI_IP6; afi++) |
1635 | isis_circuit_switchover_routes( | |
1636 | circuit, afi == AFI_IP ? AF_INET : AF_INET6, | |
1637 | NULL, ifp->ifindex); | |
bcf22081 | 1638 | isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp); |
b0b69e59 | 1639 | |
b0b69e59 | 1640 | SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); |
bcf22081 | 1641 | } |
b0b69e59 | 1642 | |
138c5a74 DS |
1643 | return 0; |
1644 | } | |
1645 | ||
1646 | static int isis_ifp_destroy(struct interface *ifp) | |
1647 | { | |
bcf22081 | 1648 | struct isis_circuit *circuit = ifp->info; |
3c3c3252 | 1649 | |
bcf22081 IR |
1650 | if (circuit) |
1651 | isis_circuit_disable(circuit); | |
3c3c3252 | 1652 | |
138c5a74 DS |
1653 | return 0; |
1654 | } | |
1655 | ||
4d762f26 | 1656 | void isis_circuit_init(void) |
eb5d44eb | 1657 | { |
d62a17ae | 1658 | /* Initialize Zebra interface data structure */ |
ce19a04a DL |
1659 | hook_register_prio(if_add, 0, isis_if_new_hook); |
1660 | hook_register_prio(if_del, 0, isis_if_delete_hook); | |
eb5d44eb | 1661 | |
d62a17ae | 1662 | /* Install interface node */ |
104fd767 | 1663 | #ifdef FABRICD |
9da01b0b | 1664 | if_cmd_init(isis_interface_config_write); |
104fd767 IR |
1665 | #else |
1666 | if_cmd_init_default(); | |
1667 | #endif | |
138c5a74 DS |
1668 | if_zapi_callbacks(isis_ifp_create, isis_ifp_up, |
1669 | isis_ifp_down, isis_ifp_destroy); | |
eb5d44eb | 1670 | } |